约瑟夫环问题

一、原题目

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

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

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

自己的做法:模拟为圆,删除元素之后计算下一个下标,直到删除至只剩一个元素

class Solution {
    public int lastRemaining(int n, int m) {
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = 0; i < n; i++){
            list.add(i);
        }
        //开始删除元素
        //从m位置开始
        int index = 0;
        while(list.size() != 1){
            index = (index + m - 1) % list.size();
            list.remove(index);
        }
        return list.get(0);
    }
}

由于ArrayList的remove()方法时间复杂度是O(n),删除了n-1次,所以整体时间复杂度是O(n²)。leetcode上通过时长1.33s,确实太久了...

二、数学方法解决约瑟夫环问题

        约瑟夫环本是一圈人依次报数,到第m个人就会被杀。

        假设使用数字来代替人:

                0        1        2        3        4        5        6        7        8        9        10

        这里设置m=3,从0开始,第3个人会被淘汰

        第一轮:2被淘汰,2之后的人作为数组的新起点

                3        4        5        6        7        8        9        10        0        1        

        第二轮:5被淘汰,5之后的人作为新起点

                6        7        8        9        10        0        1        3        4

        第三轮:8被淘汰,8之后的人作为新起点

                9        10        0        1        3        4        6        7

        

        这里可以逆推了:

                第三轮之后,即将被淘汰的是9,9在第三轮之前的位置为:

                (0+m) % 9 = 3

        于是:

                由于最终胜利者的位置是0,上一轮的位置要往后移动3位,但由于是圆圈循环,要模上一个人数得出胜利者的位置:

                倒数第二轮:(0+3) % 2 = 1

                倒数第三轮:(1+3) % 3 = 1

                可得到递归公式:f(n,m) = (f(n-1,m) + m) % n

class Solution {
    public int lastRemaining(int n, int m) {
        int res = 0;
        for(int i = 2; i <= n; i++){
            res = (res + m - 1) % i + 1;
        }
        return res;
    }
}

                

      

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值