【Java】 剑指offer(62) 圆圈中最后剩下的数字

 

本文参考自《剑指offer》一书,代码采用Java语言。html

更多:《剑指Offer》Java实现合集  java

题目

  0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。数组

思路

  方法一:采用链表来存放数据,每次对长度取余来实现循环post

  将全部数字放入LinkedList链表中(LinkedList比ArrayList更适合增删操做)。假设当前删除的结点下标为removeIndex,则下一个要删除的结点的下标为:(removeIndex+m-1)%list.size(),经过取余符号能够实现类型循环的操做。性能

  注:不必用循环链表,反而会更麻烦了。测试

  方法二:数学推导规律url

  n个数字的圆圈,不断删除第m个数字,咱们把最后剩下的数字记为f(n,m)code

  n个数字中第一个被删除的数字是(m-1)%n, 咱们记做k,k=(m-1)%nhtm

  那么剩下的n-1个数字就变成了:0,1,……k-1,k+1,……,n-1,咱们把下一轮第一个数字排在最前面,而且将这个长度为n-1的数组映射到0~n-2。blog

  原始数字:k+1,……,   n-1,       0,    1,……k-1

  映射数字:0    ,……,n-k-2, n-k-1, n-k,……n-2

  把映射数字记为x,原始数字记为y,那么映射数字变回原始数字的公式为 y=(x+k+1)%n

  在映射数字中,n-1个数字,不断删除第m个数字,由定义能够知道,最后剩下的数字为f(n-1,m)。咱们把它变回原始数字,由上一个公式能够获得最后剩下的原始数字是f(n-1,m)+k+1)%n,而这个数字就是也就是一开始咱们标记为的f(n,m),因此能够推得递归公式以下:

          f(n,m) =f(n-1,m)+k+1)%n

  将k=(m-1)%n代入,化简获得:

          f(n,m) =f(n-1,m)+m)%n

          f(1,m) = 0

  代码中能够采用循环或者递归的方法实现该递归公式。时间复杂度为O(n),空间复杂度为O(1)

 

测试算例 

  1.功能测试(m大于/小于/等于n)

  2.特殊测试(n、m<=0)

  3.性能测试(n=4000,n=997)

 

Java代码

//题目:0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里
//删除第m个数字。求出这个圆圈里剩下的最后一个数字。

public class LastNumberInCircle {
    /*
     * 方法一:采用推导出来的方法
     */
    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;  //这里是i不是n!!!
        }
        return last;
    }
    
    /*
     * 方法二:采用链表来存放,每次对长度取余来实现循环
     */
    public int LastRemaining_Solution2(int n, int m) {
        if(n<1 || m<1)
            return -1; //出错
        LinkedList<Integer> list = new LinkedList<Integer>();
        for(int i=0;i<n;i++)
            list.add(i);
        int removeIndex=0;
        while(list.size()>1){
            removeIndex=(removeIndex+m-1)%list.size();
            list.remove(removeIndex);
        }
        return list.getFirst();
    }
}

  

收获

  1.对于下标循环一圈相似的问题,经过%能够很好地实现循环,而不须要咱们本身构造循环链表;

  2.(a%n+b)%n=(a+b)%n

  3.尽可能学会本题的数学方法,特别是要掌握好数字间映射的方法。

  4.公式法中,last=(last+m)% i;  //这里是i不是n!!!

 

更多:《剑指Offer》Java实现合集 

相关文章
相关标签/搜索