1 题目描述
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例1:
复制代码
1
2
3输入: n = 5, m = 3 输出: 3
示例2:
复制代码
1
2
3输入: n = 10, m = 17 输出: 2
限制:
复制代码
1
2
31 <= n <= 10^5 1 <= m <= 10^6
2 解题思路
方法:链表模拟(超时)
- 将[0,n]依次存储在链表中;
- 只要链表的长度不为1,就一直循环,如果到了第m个就remove;否则将其添加到链表尾部;
- 时间复杂度为O(mn)。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution { public int lastRemaining(int n, int m) { List<Integer> list = new ArrayList<>(); for (int i = 0;i < n;i++) { list.add(i); } while (list.size() > 1) { for (int j = 0;j < m;j++) { if (j != m - 1) list.add(list.get(0)); list.remove(0); } } return list.get(0); } }
方法:数学+递归
题目中的要求可以表述为:给定一个长度为n
的序列,每次向后数m
个元素并删除,那么最终留下的是第几个元素?
这个问题很难快速给出答案。但是同时也要看到,这个问题似乎有拆分为较小子问题的潜质:如果我们知道对于一个长度n-1
的序列,留下的是第几个元素,那么我们就可以由此计算出长度为n
的序列的答案。
算法:
我们将上述问题建模为函数f(n,m)
,该函数的返回值为最终留下的元素的序号。
首先,长度为n
的序列会先删除第m%n
个元素,然后剩下一个长度为n-1
的序列。那么,我们可以递归地求解f(n-1,m)
,就可以知道对于剩下的n-1
个元素,最终会留下第几个元素,我们设答案为x=f(n-1,m)
。
由于我们删除了第m%n
个元素,将序列的长度变为n-1
。当我们知道了f(n-1,m)
对应的答案x
之后,我们也就可以知道,长度为n
的序列最后一个删除的元素,应当是从m%n
开始数的第x
个元素。因此有f(n,m)=(m%n+x)%n=(m+x)%n
。
复制代码
1
2
3
4
5
6
7
8
9
10
11class Solution { public int lastRemaining(int n, int m) { return f(n,m); } private int f(int n, int m) { if (n == 1) return 0; int x = f(n-1,m); return (x + m) % n; } }
复杂度分析:
- 时间复杂度:O(n),需要求解的函数值有 n 个。
- 空间复杂度:O(n),函数的递归深度为 n,需要使用 O(n) 的栈空间。
最后
以上就是疯狂奇迹最近收集整理的关于62题-圆圈中最后剩下的数字1 题目描述2 解题思路的全部内容,更多相关62题-圆圈中最后剩下的数字1内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复