圆圈中最后剩下的数字

题目描述: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;
    }
}
原文地址:https://www.cnblogs.com/Dream-chasingGirl/p/10295358.html