剑指offer62 圆圈中最后剩下的数字

最基本的方法当然是利用链表,然后按照顺序一个个删除,留下最后的就是结果。时间复杂度O(mn)。

那么有没有什么更简单的方法呢?

我们发现,如果将n个数字每次删除第m个最后留下的数字定义为f(n,m)。

那么假设第一次删除的数是k(=(m-1)%n),对于剩下的数k+1,k+2,...,n-1,0,k-1,将之重新排为0~n-2后,剩余的数字为f2(n-1,m)。

那么f(n,m)==f2(n-1,m)。

f2分为两步操作,一是重排剩下的序列,即,搞一个新的映射出来,直接在原数组上得到最终结果,二是递归。

而映射过程也很简单,就是

开始是 0~n-1 对应 0~n-1

第二轮 k+1,k+2,...,n-1,0,k-1  , k 对应0~n-1

只不过k被删掉了,不会用到这个映射。

对应的映射应为 (x-k-1)%n ,逆映射 (x+k+1)%n。

f(1,m)=0

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

所以结果:

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

运行时间:17ms

占用内存:9224k

posted @ 2019-03-06 20:07  大胖子球花  阅读(164)  评论(0)    收藏  举报