题目描述
解法一:模拟环形链表
这道题如果模拟实现的话其实考的是「循环单向链表」(链表尾指向链表头部,且每个结点只有一个后继结点),由于 Java 里面没有现成的类库可以使用,因此先尝试用 LinkedList 发现超时,然后用 ArrayList。
Java
class Solution {
public int lastRemaining(int n, int m) {
/*
若使用 LinkedList 会超时
LinkedList 虽然删除指定节点的时间复杂度是 O(1)的,但是在 remove 时间复杂度仍然是 O(n)的,因为需要从头遍历到需要删除的位置。
而 ArrayList直接按索引找到需要删除的位置,时间复杂度是 O(1),但 remove的整体时间复杂度是 O(n),因为后续元素需要向前搬运。
看起来二者单次删除操作的时间复杂度一样,但是
ArrayList 的 remove操作在搬运后续元素时,其实是内存连续空间的拷贝!所以相比于LinkedList大量非连续性地址访问,ArrayList的性能更优。
*/
ArrayList<Integer> list = new ArrayList<> ();
// 将 n个数添加到链表中
for(int i=0; i<n; i++) {
list.add(i);
}
// 每次删除第 m个数字,直到链表中只剩下一个元素
int idx = 0;
while(n>1) {
idx = (idx + m -1) % n; // 通过数学公式计算得到下一个要删除的位置
list.remove(idx);
n--;
}
// 返回链表中剩下的唯一元素
return list.get(0);
}
}
复杂度分析:
- 时间复杂度 O(n2):每次删除的时间复杂度是 O(n),删除了 n-1 次,所以整体时间复杂度是 O(n2)。
- 空间复杂度 O(n):需要一个辅助链表来模拟圆圈。
解法二:数学法
-
定义⼀个关于 n和 m的方程 f(n,m) ,表示在 n个数字 0,1,…,n-1中不断删除第 m个数字最后剩下的数字。
-
第一个被删除的数字是(m-1)%n (取余的原因是m可能比n大,m-1是因为 n个数是从 0 开始计数), 我们记作k,k=(m-1)%n
-
那么删除 k 后剩下的n-1个数字就变成了:0,1,……k-1, k+1,……,n-1,并且下一次删除从数字 k+1开始计数,我们把下一轮第一个数字即 k+1 排在剩下的序列中的最前面,并且将这个长度为 n-1的数组映射到 0~n-2 这个序列范围内。
-
把映射数字记为x,原始数字记为y,那么映射数字变回原始数字的公式为:y = (x + k+1) % n
-
在映射的数字序列中,从 n-1个数字中不断删除第 m个数字,由前面定义可以知道,最后剩下的数字为 f(n-1,m)。我们把它映射回原始数组中的数字,由上一个公式可以得到最后剩下的原始数字是:(f(n-1,m) + k+1) % n,这个数字也就是一开始我们标记的整个序列中最后剩下的数字 f(n,m)。因此,可以得到递推公式为:f(n,m) = (f(n-1,m) + k+1) % n。
-
将 k=(m-1)%n 代入简化得,f(n,m) = (f(n-1,m) + m) % n 且 f(1, m) = 0
(注意:在数字中,(a%n+b)%n=(a+b)%n,f(1, m) = 0 则代表 n=1即系列中一开始只有一个数字 0,很显然最后剩下的数字就是 0)。
递归实现
class Solution {
public int lastRemaining(int n, int m) {
return recur(n, m);
}
public int recur(int n, int m) {
if(n == 1) return 0; // 递归终止条件
return (recur(n-1, m) + m) % n; // 递推公式
}
}
复杂度分析:
- 时间复杂度 O(n):需要求解的函数有 n个,递归 n次。
- 空间复杂度 O(n):递归函数调用栈的深度为 n。
迭代实现
class Solution {
public int lastRemaining(int n, int m) {
int res = 0;
for(int i=2; i<=n; i++) // 从 i=2 开始,是因为 i=1 时只要 m>0 直接返回 0 即可;i<=n 是因为需要一直递推到 n个数的情况
res = (res + m) % i;
return res;
}
}
复杂度分析:
- 时间复杂度 O(n):for循环执行 n次。
- 空间复杂度 O(1):只需要一个变量。
参考
https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-by-lee/
https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/si-chong-fang-fa-xiang-xi-jie-da-by-yuanninesuns/
https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/solution/javajie-jue-yue-se-fu-huan-wen-ti-gao-su-ni-wei-sh/