剑指 Offer 62. 圆圈中最后剩下的数字
题目描述
解题思路
约瑟夫环问题。
暴力解法
class Solution {
public int lastRemaining(int n, int m) {
List<Integer> list = new ArrayList(n);
for(int i=0; i < n; i++)
list.add(i);
int idx = 0;
while(n > 1){
idx = (idx + m -1) % n;
list.remove(idx);
n--;
}
return list.get(0);
}
}
复杂度分析
- 时间复杂度:
O(mn)
- 空间复杂度:
O(n)
动态规划
从n个数字中删除第m个数字得到n-1个数字,继续从剩下的n-1个数字中删除第m个数字。
设get(int n, int m)
表示从n个数字(0...n-1)
中持续删除m个数字最后得到的数字,则get(n-1, m)
表示从n-1个数字中(0...n-2)
删除m个数字最后得到的数字。
设t = m % n
,因为(0...n-1)
中删除的第m个数字为 (m-1) % n
,所以下一个其实下标为m%n
,即从(t、t + 1、...、t + n - 2) % n
中删除第m个数字。可以看到(0...n-2)
和(t、t + 1、...、t + n - 2) % n
对应位置相差t
。
设x = get(n - 1, m)
, 对应原数字的下标为 (x + t) % n
。
在子问题中得到x
之后还需通过(x + t) % n
映射回原数字中的下标。
class Solution {
public int lastRemaining(int n, int m) {
//约瑟夫环问题
return get(n, m);
}
int get(int n, int m){
if(n == 1) return 0;
int x = get(n - 1, m);
return (x + m) % n;
}
}
复杂度分析
- 时间复杂度:
O(n)
- 空间复杂度:
O(1)