程序员面试金典——番外篇之约瑟夫问题1

本文介绍了约瑟夫问题的两种解决方案。Solution1采用模拟法,通过迭代确定最后幸存者的位置;Solution2则通过数学分析得出递推公式,极大地简化了解题过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序员面试金典——番外篇之约瑟夫问题1

Solution1:我的答案。脑子是个好东西,希望我总是带着他~
该算法模拟了游戏过程,不算好。
要理清逻辑关系,因果关系,再下笔~

class Joseph {
public:
    int getResult(int n, int m) {
        // write code here
        if(n <= 0 || m <= 0)
            return -1;
        vector<bool> temp(n, false);
        int index = 0, count_m = 0, nums_false = n;
        while(1) {
            if(temp[index] == true) 
                index = (index + 1) % n;
            else {
                count_m++;
                if(count_m == m) {
                    temp[index] = true;
                    nums_false--;
                    if(nums_false == 0)
                        return index + 1;//这,就是答案!
                    else {
                        count_m = 0;
                        index = (index + 1) % n;
                    }
                }
                else 
                    index = (index + 1) % n;
            }
        }
        return -1;
    }
};

Solution2:小技巧啊~
参考网址:https://www.nowcoder.com/profile/5263754/codeBookDetail?submissionId=13380131
思路:求出了递推公式,真牛逼
把n个人的编号改为0~n-1,然后对删除的过程进行分析。
第一个删除的数字是(m-1)%n,记为k,则剩余的编号为(0,1,…,k-1,k+1,…,n-1),下次开始删除时,顺序为(k+1,…,n-1,0,1,…k-1)。
f(n,m) f ( n , m ) 表示从(0~n-1)开始删除后的最终结果。
q(n1,m) q ( n − 1 , m ) 表示从(k+1,…,n-1,0,1,…k-1)开始删除后的最终结果。
f(n,m)=q(n1,m) f ( n , m ) = q ( n − 1 , m )

下面把(k+1,…,n-1,0,1,…k-1)转换为(0~n-2)的形式,即
k+1对应0
k+2对于1

k-1对应n-2
转化函数设为 p(x)=(xk1)%n p ( x ) = ( x − k − 1 ) % n , p(x) p ( x ) 的逆函数为 p1(x)=(x+k+1)%n p − 1 ( x ) = ( x + k + 1 ) % n
f(n,m)=q(n1,m)=p1(f(n1,m))=(f(n1,m)+k+1)%n f ( n , m ) = q ( n − 1 , m ) = p − 1 ( f ( n − 1 , m ) ) = ( f ( n − 1 , m ) + k + 1 ) % n ,又因为 k=(m1)%n k = ( m − 1 ) % n
f(n,m)=(f(n1,m)+m)%n f ( n , m ) = ( f ( n − 1 , m ) + m ) % n ;

最终的递推关系式为

f(1,m)=0;(n=1) f ( 1 , m ) = 0 ; ( n = 1 )

f(n,m)=(f(n1,m)+m)%n;n>1 f ( n , m ) = ( f ( n − 1 , m ) + m ) % n ; ( n > 1 )

代码如下

class Joseph {
public:
    int getResult(int n, int m) {
        // write code here   
        int pre = 0;
        for (int i = 2; i <= n; i++) {
            pre = (pre + m)%i;
        }
        return pre + 1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值