题目:0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
解法一:使用LinkedList仿圆就可以了,很简单
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if(n<=0||m<=0)return -1;
LinkedList<Integer> list = new LinkedList();
for(int i =0;i<n;i++){
list.add(i);
}
int cur = 0;
while(list.size()>1){
cur = (cur+m-1)%list.size();
list.remove(cur);
}
return list.getFirst();
}
}
时间复杂度:O(n)
空间复杂度:O(n)
解法二:使用数学公式递推(动态规划思想)
1、首先定义剩下的数:f(n,m)
2、第一个被删除的数字为s,由解法一我们可以知道s=(m-1)%n
3、当删完s以后,剩下的数字为0,1...,s-1,s+1,...n-2当从s+1处继续开始数m个数,我们以s+1为开头
当前数组排列为:s+1,s+2, ... 0, 1, ...s-1
对应映射数组为:0 ,1 , ... n-2-s,n-1-s...,n-2
这里设映射数字为x,当前数字为y。y=(x+s+1)%n
在映射的数组中,因为我们定义的n个数最后一个数字为f(n,m),所以在删除了s之后n-1个数字最后一个数为f(n-1,m)
把f(n-1,m)转换成当前数组中的数字即带入上方公式得:(f(n-1,m)+s+1)%n
4、最终我们有第一步定义的f(n,m) = (f(n-1,m)+s+1)%n,把s=(m-1)%n带入可简化为:(取余部分可直接提出,因为一次跟两次效果是一样的)
f(n,m) = (f(n-1,m)+m)%n
当n=1时:f(1,m) = 0
推的是不是很烦!!!看看代码就高兴了,因为很少,哈哈
import java.util.*;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
if(n<=0||m<=0)return -1;
// 因为f(1,m) = 0;所以last取0,n从2开始
// 并且f(n,m) = (f(n-1,m)+m)%n所以循环条件i可以=n
int last = 0;
for(int i =2;i<=n;i++){
last = (last+m)%i; // 注意这里除数是i,因为f(n,m)从1开始,f(2,m) = (last+m)%2 ...
}
return last;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
练习地址:https://www.nowcoder.com/practice/f78a359491e64a50bce2d89cff857eb6