题目描述:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
思路分析:(一)这个问题类似于从链表中删除,而且是循环链表,所以可以通过链表来描述,但由于问题中涉及到编号,故还是采用ArrayList来刻画比较好。具体分为以下几步:
1.判断不合法情况,即m和n都小于1;
2.创建一个大小为n的ArrayList,并给它们赋初值0--n-1来刻画编号;
3.当链表的大小大于1执行如下操作:每隔m删除一个,并且对应的索引点发生变化。
(二)分析被删除数字的规律,找出规律,编写代码,具体分析如下:
假设从0-n-1中删除了第m个数字,则下一轮的数字排列为m,m+1,.....n-1,0,1,2,3...m-2,将该数字排列重新映射为0~n-2,则为
m 0
m+1 1
.... ....
n-1 n-1-m
0 n-m
1 n-m+1
... ....
m-2 n-2
可以看出从右往左的映射关系为left=(right+m)%n,即0~n-1序列中最后剩下的数字等于(0~n-2序列中最后剩下的数字+m)%n,很明显当n=1时,只有一个数,那么剩下的数字就是0.
问题转化为动态规划问题,关系表示为:
f(n)=(f(n-1)+m)%n; 当n=1,f(1)=0;
代码实现:
(1)链表描述
import java.util.ArrayList; public class Solution { public int LastRemaining_Solution(int n, int m) { if(n==0||m<1) { return -1; } ArrayList<Integer> list = new ArrayList<Integer>(); for(int i=0;i<n;i++) { list.add(i); } int index = -1; while(list.size()>1) { index = (index+m)%list.size(); list.remove(index); index--; } return list.get(0); } }
(2)递归公式
import java.util.ArrayList; public class Solution { public int LastRemaining_Solution(int n, int m) { if(n<1||m<1) return -1; int last = 0; for(int i=2;i<=n;i++) { last = (last+m)%i; } return last; } }