zoukankan      html  css  js  c++  java
  • 孩子们的游戏(圆圈中最后剩下的数)

    题目描述:

    每年六一儿童节,NowCoder都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为NowCoder的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到NowCoder名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?

    解法一:

    思路:

    找规律。首先定义最初的n个数字(0,1,…,n-1)中最后剩下的数字是关于n和m的方程为f(n,m)。 在这n个数字中,第一个被删除的数字是(m-1)%n,为简单起见记为k。
    * 那么删除k之后的剩下n-1的数字为0,1,…,k-1,k+1,…,n-1,并且下一个开始计数的数字是k+1。相当于在剩下的序列中,k+1排到最前面,从而形成序列k+1,…,n-1,0,…k-1。
    * 该序列最后剩下的数字也应该是关于n和m的函数。由于这个序列的规律和前面最初的序列不一样(最初的序列是从0开始的连续序列),因此该函数不同于前面函数,记为f’(n-1,m)。最初序列最后剩下的数字f(n,m)一定是剩下序列的最后剩下数字f’(n-1,m),所以f(n,m)=f’(n-1,m)。接下来我们把剩下的的这n-1个数字的序列k+1,…,n-1,0,…k-1作一个映射,映射的结果是形成一个从0到n-2的序列:

       k+1    ->    0
         k+2    ->    1
           …
          n-1    ->    n-k-2
          0       ->    n-k-1
        …
          k-1      ->   n-2

    把映射定义为p,则p(x)= (x-k-1)%n,对应的逆映射是p-1(x)=(x+k+1)%n,f’(n-1,m)= p-1 [f(n-1,m)]=[f(n-1,m)+k+1]%n。把k=m%n-1代入得到f(n,m)=f’(n-1,m)=[f(n-1,m)+m]%n。

    我们把这种关系表示为:

                   0                            n=1
    f(n,m)={
                  [f(n-1,m)+m]%n     n>1

    public int LastRemaining_Solution(int n, int m) {
            if(n<1||m<1)
                return -1;
            if(m>=n) 
                return -1;
            int last=0;
            for(int i=2;i<=n;i++){
                last=(last+m)%i;
            }
            return last;
        }

    解法二:

     /*
        *用数组来模拟环,思路还是比较简单,但是各种下标要理清
        */
        public static int findLastNumber(int n,int m){
            if(n<1||m<1) return -1;
            int[] array = new int[n];
            int i = -1,step = 0, count = n;
            while(count>0){   //跳出循环时将最后一个元素也设置为了-1
                i++;          //指向上一个被删除对象的下一个元素。
                if(i>=n) i=0;  //模拟环。
                if(array[i] == -1) continue; //跳过被删除的对象。
                step++;                     //记录已走过的。
                if(step==m) {               //找到待删除的对象。
                    array[i]=-1;
                    step = 0;
                    count--;
                }        
            }
            return i;//返回跳出循环时的i,即最后一个被设置为-1的元素
        }

    解法三:

    public int LastRemaining_Solution(int n,int m){
            if (m == 0 || n == 0) {
                return -1;
            }
            ArrayList<Integer> data = new ArrayList<Integer>();
            for (int i = 0; i < n; i++) {//将所有的数都加入到一个数组中
                data.add(i);
            }
            int index = -1;
            while (data.size() > 1) {
    //          System.out.println(data);
                index = (index + m) % data.size();
    //          System.out.println(data.get(index));
                data.remove(index);
                index--;//此处的索引为什么是减1呢?,因为开始的时候index就是-1,本身index+m就表示的是第m个数,当删除index数的时候,index-1+m任然表示下一个第m的数

    }
    return data.get(0);
        }
  • 相关阅读:
    POJ_3176_Cow_Bowling_(数字三角形)_(动态规划)
    POJ_3662_Telephone_Lines_(二分+最短路)
    POJ_2739_Sum_of_Consecutive_Prime_Numbers_(尺取法+素数表)
    POJ_3685_Matrix_(二分,查找第k大的值)
    POJ_3579_Median_(二分,查找第k大的值)
    欧拉回路
    状态压缩dp(hdu2167,poj2411)
    poj1182食物链(种类并查集)
    并查集
    树形动态规划
  • 原文地址:https://www.cnblogs.com/tjuxqcui/p/5539078.html
Copyright © 2011-2022 走看看