有 1 到 100 共 100 個數,排成一個圓圈。從 1 開始,每隔 1、2、3、4... 個數取走一個數,循環進行,直到最後剩下一個數為止。具體規則:
問題:最後剩下的是哪個數?若擴展到 1 到 n 呢?
這是一個變體的约瑟夫斯問題,間隔步長遞增。使用 ArrayList 模擬圓圈,維護當前索引與步長計數器,循環移除元素直到剩最後一個。
public static int selectNumber(int n) {
int result = -1;
ArrayList<Integer> nums = new ArrayList<>();
int index = 0; // 當前移除索引
int count = 0; // 步長計數器(隔幾個數)
int pIndex = 0; // 記錄上一次移除索引
// 初始化 1 到 n
for (int i = 1; i <= n; i++) {
nums.add(i);
}
while (nums.size() > 1) {
// 單輪遍歷移除
while (index < nums.size()) {
nums.remove(index);
count++;
pIndex = index;
index += count;
}
// 計算下一輪起始索引(環狀處理)
index = count - (nums.size() - pIndex);
while (index > nums.size() - 1) {
index = index - nums.size();
}
}
result = nums.get(0);
return result;
}
public static void main(String[] args) {
int surviver = selectNumber(100);
System.out.println("The surviver is: " + surviver); // 輸出: 31
}
程式執行後輸出:The surviver is: 31
即 1 到 100 按規則取數後,最後剩下的數字是 31。
對於 n=100 規模,效能完全足夠。若 n 極大,可考慮鏈表或數學推導優化。
此問題展示了模擬法解決變體约瑟夫斯問題的通用思路。關鍵在於正確處理環狀索引計算與動態步長遞增邏輯。讀者可嘗試修改步長規則(如固定步長、斐波那契步長等)觀察結果變化。