约瑟夫环的问题

约瑟夫环问题介绍

        来自百度百科:约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。

         题目比较简单,有两种解题思路。分别为:按照减人逻辑一步一步进行(普通的逻辑);通过数学公式进行逆推,由1推2,推3,直至推n;

第一种思路:

          直接根据普通逻辑,建立循环队列或者数组,一步一步减人并进行重新排序。排序之后再进行减人,直至剩余一人。

          假设10人,即n=10,序号为4,即m=4;

          第一次需要删去的人的序号:m-1 = 3

0       1        2      3       4         5         6         7       8       9

         第二次需要删去的人的序号:((上一次删去的序号)+(m-1)) / n-1 =(3+3)/9 = 6     注:得出序号为6只是原来10个数的第六个,可现在数组已经减少了一个数,  /9是为了进入循环,也可以理解为防止溢出。功能是一样的。

0       1        2        3         4         5         6         7        8       9                 //   原来的序号

6       7        8                   0         1         2         3        4       5                //删除后重新排序的序号

0       1        2                   3         4         5                7        8                 //   现在的序号

以此类推,第n-1次删去的人的序号: (n-2次删去的序号)+(m)) / 现在的数组长度。

代码如下:

public int LastRemaining_Solution(int n, int m) {
        if(n==0 || m ==0) return -1;
        LinkedList<Integer> list = new LinkedList<>();
        int re_index = 0;//记录删去孩子的序号
        for(int i=0;i<n;i++){
            list.add(i);
        }
        while(list.size()!=1){
            re_index = (re_index+ m -1) % list.size();
            list.remove(re_index);
        }
        return list.get(0);
    }

第二种思路

根据数学公式进行逆推。 f(n,m) = f(n-1,m) + m  / n;

f(n,m) 表示n个人时,能够存活下来那个人的位置坐标(索引)。

f(1)=0,  f(2) = (f(1) +m)/2;以此类推。推导过程比较繁琐,后续加入。

代码如下:

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

果然,做编程题要多想想,只有想通了逻辑,才会加快写代码的速度。每一个编程题背后,一定存在某个数学逻辑问题,要多想想才可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值