约瑟夫问题详解

什么是约瑟夫问题?

链接:环形链表的约瑟夫问题__牛客网
来源:牛客网

据说著名犹太历史学家 Josephus 有过以下故事:在罗马人占领乔塔帕特后,39 个犹太人与 Josephus 及他的朋友躲到一个洞中,39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一种自杀方式,41 个人排成一个圆圈,由第 1 个人开始报数,报数到 3 的人就自杀,然后再由下一个人重新报 1,报数到 3 的人再自杀,这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表得出最终存活的人的编号

下面我们就来做一下最简单的约瑟夫问题:

环形链表的约瑟夫问题__牛客网

大家可以点开这个题目,我的解析放在下面:

我们此时只用链表就可以做出这道题:

代码如下:

#include 
#include 
typedef struct node
{
    int number;
    struct node* next;
}SL;
int Findnum(int n, int m)
{
    SL* phead = (SL*)malloc(sizeof(SL));
    phead->next = NULL;
    phead->number = 1;
    SL* cur = phead;
    for (int i = 2; i <= n; i++)
    {
        SL* tmp = (SL*)malloc(sizeof(SL));
        tmp->next = NULL;
        tmp->number = i;
        cur->next = tmp;
        cur = cur->next;
    }
    if (cur->next == NULL)
        cur->next = phead;
    cur = phead;
    //
    int k = 0;
    while (1)
    {
        if (cur->next == cur)
            break;
        k++;
        if (m-1==k)
        {
            //删除节点
            SL* tmtp = cur->next;
            cur->next = cur->next->next;
            free(tmtp);
            k = 0;
        }
        cur = cur->next;
    }
    return cur->number;
}
int main()
{
    int m, n;
    scanf("%d%d", &n, &m);
    //
    printf("%d\n", Findnum(n, m));
    return 0;
}

(链表法)

但是如果我们用同样的方法去跑leedcode上这题就会出现如下情况:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

约瑟夫问题详解_第1张图片

很显然,单纯的链表是无法解决问题的,所以我们引出公式法

公式为:

我们如果用迭代时:

class Solution {
public:
    int iceBreakingGame(int num, int target) 
    {
        int find=0;
        for(int i=2;i<=num;i++)
        find=(find+target)%i;
        return find;
    }
};

公式推导大家可以自行去了解!!! 

递归法:

class Solution {
public:
    int find(int num,int target)
    {
        if(num==1)return 0;
        int x=find(num-1,target);
        return (target+x)%num;
    }
    int iceBreakingGame(int num, int target) 
    {
        return find(num,target);
    }
};

公式为:

f(n)=(f(n-1) +m) %n

约瑟夫问题II__牛客网

关于约瑟夫问题变形非常多,大家如果有兴趣,可以去了解下上面这题,当然也可以自己去查找其他题目

感谢大家的支持!

你可能感兴趣的:(链表)