概述
1 题目描述
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例1:
输入: n = 5, m = 3
输出: 3
示例2:
输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
2 解题思路
方法:链表模拟(超时)
- 将[0,n]依次存储在链表中;
- 只要链表的长度不为1,就一直循环,如果到了第m个就remove;否则将其添加到链表尾部;
- 时间复杂度为O(mn)。
class 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
。
class 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 题目描述2 解题思路所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复