zoukankan      html  css  js  c++  java
  • 【Offer】[62] 【圆圈中最后剩下的数字】

    题目描述

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

    牛客网刷题地址

    思路分析

    1. 采用链表来存放数据,每次对长度取余来实现循环:
      • 将所有数字放入LinkedList链表中(LinkedList比ArrayList更适合增删操作)。假设当前删除的结点下标为removeIndex,则下一个要删除的结点的下标为:(removeIndex+m-1)%list.size(),通过取余符号可以实现类型循环的操作
      • 注:没必要用循环链表,反而会更麻烦了。
    2. 数学推导规律
        n个数字的圆圈,不断删除第m个数字,我们把最后剩下的数字记为f(n,m)
        n个数字中第一个被删除的数字是(m-1)%n, 我们记作k,k=(m-1)%n
        那么剩下的n-1个数字就变成了:0,1,……k-1,k+1,……,n-1,我们把下一轮第一个数字排在最前面,并且将这个长度为n-1的数组映射到0~n-2。
        原始数字: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,比如从最初有5个数字的圆圈中每次删除第2、3个数字;输入的m大于或者等于n,比如从最初有6个数字的圆圈中每次删除第6、7个数字。
    2. 特殊输入测试:圆圈中有0个数字。
    3. 性能测试:从最初有4000个数字的圆圈中每次删除第997个数字。

    Java代码

    public class Offer062 {
        public static void main(String[] args) {
            test1();
            test2();
            test3();
            
            
        }
    
        public static int LastRemaining(int n, int m) {
            return Solution1(n, m);
        }
    
        
        /*
         * 方法一:采用推导出来的方法
         */
        public static int Solution1(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 static int 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();
        }
        
        private static void test1() {
    
        }
    
        private static void test2() {
    
        }
        private static void test3() {
    
        }
    
    }
    

    代码链接

    剑指Offer代码-Java

  • 相关阅读:
    kvm介绍
    正式班D24
    正式班D23
    正式班D21
    正式班D20
    正式班D19
    正式班D18
    正式班D17
    正式班D16
    正式班D15
  • 原文地址:https://www.cnblogs.com/haoworld/p/offer62-yuan-quan-zhong-zui-hou-sheng-xia-de-shu-z.html
Copyright © 2011-2022 走看看