[每日一题系列]第一天——约瑟夫问题

约瑟夫问题

    • 问题描述
    • 我的思路
    • 我的Java代码

  • 完成打卡

问题描述

0,1,…,n-1这n个数排成一个圆圈,从0开始,每次从这个圆圈里删掉第m个数字(存在m大于n的情况),求圆圈里剩下的最后一个数字【题目来源于LeetCode】

我的思路

  • 一开始,我觉得这是一个数学问题,想通过找规律的方式总结出结果的计算方法,但天真的我发现就算真的有计算公式,也不是我一时半会能找出来的,于是我想利用循环来解决,大致思路是用一个对应的boolean类型的数组来表示该数是否被删除,被删除的数置为true。用一个变量来记录这是第几个数。循环结束的条件就是只剩下一个数,即数组只有一个位置为false。从0开始循环,根据数组判断该数是否已经被删除,若未被删除则计数加一,直到计数到m,就将该数对应的数组置为true,计数又从0开始。
  • 但是这种基于循环的解决方法,在n较大的时候非常的耗时,所以对题目进一步分析后,觉得或许可以利用递归来解决这个问题,但递归一直是我的弱点,虽然知道该用递归,但从哪里下手却毫无头绪,于是我就在网上找对于约瑟夫问题的分析,慢慢理解。

下面是我对约瑟夫问题用递归方法的理解:

从0到n-1一共有n个数,我们要删掉第m个数,那么我们第一个删掉的一定是m%n-1,此时还剩n-1个数,对于这n-1个数,下一次的计数起点一定是m%n,将该数记为k,如果对剩下的这些数重新编号,即k=0,…,就会组成一个新的约瑟夫环,此时就能将其看作一个n-1的子问题,而该子问题的解若为x,那么对于n个数而言,他的解x` = (x+k)%n。
因此,要知道n个数最后的解,我们就需要知道n-1个数最后的解,而n-1个数最后的解又可由n-2个数的解求得,至此递归的基本公式我们已经找到了。
设f(n)——表示n个数,最后剩下的数的值,那么f(n) = ( f(n-1) +m%n )%n,当n=1时,f(n) = 0,到这里递归的基本形式已经推出,接下来就可以写代码了。

我的Java代码

class Solution {
     
    public int lastRemaining(int n, int m) {
     
        if(n==1){
     
            return 0;
        }
        else{
     
            return (lastRemaining(n-1,m)+m%n)%n;
        }
    }
}

[每日一题系列]第一天——约瑟夫问题_第1张图片
后续若有改进方法,将进行更新

你可能感兴趣的:(每日一题系列(算法),算法,leetcode,java)