面试题45:圆圈中最后剩下的数字(约瑟夫环问题)

题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。当一个数字删除后,从被删除数字的下一个继续删除第m个数字。求出在这个圆圈中剩下的最后一个数字。

1、大部分面试官只要求应聘者基于环形链表的方法解决这个问题。

/*************************************************************************
    > Created Time: Tue 03 May 2016 01:37:26 PM PKT
 ************************************************************************/

#include<iostream>
using namespace std;

#include <list>

int LastInCircle(int n,int m)
{
    if(n<1 || m<1){
        return -1;
    }

    list<int> lt;
    for(int i=0;i<n;i++){
        lt.push_back(i);
    }

    list<int>::iterator ite=lt.begin();
    while(lt.size()>1){

        for(int i=1;i<m;i++){  //从1开始,很重要,避免错误
            ite++;
            if(ite==lt.end()){
                ite=lt.begin();
            }
        }
        ite=lt.erase(ite);
        if(ite==lt.end()){
            ite=lt.begin();
        }

    }

    return *ite;
}


//test
int main()
{
    int result=LastInCircle(5,3);
    cout<<result<<endl;
    return 0;
}

有n个结点的环形列表来模拟这个删除的过程,因此内存开销为O(n)。而且这种方法每删除一个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn)。当m和n都很大的时候,这种方法是很慢的。

2、数学方法
根据数学规律可推导出如下递归公式,推导过程复杂,但实现容易,时间复杂度为O(n),空间复杂度为O(1)。

f(n,m)={
0 n=1
[f(n-1,m)+m]%n n>1

//方法2
int LastInCircle2(int n,int m)
{
    if(n<1 || m<1){
        return -1;
    }
    int last=0;  //n=1
    for(int i=2;i<=n;i++){
        last=(last+m)%i;
    }
    return last;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值