浅谈约瑟夫环问题

文章目录

  • [1. 题目内容](#1. 题目内容)
  • [2. 解题思路](#2. 解题思路)
    • [2.1 模拟思路](#2.1 模拟思路)
      • [2.1.1 数组模拟](#2.1.1 数组模拟)
      • [2.1.2 链表模拟](#2.1.2 链表模拟)
    • [2.2 递归思路](#2.2 递归思路)
    • [2.3 迭代思路](#2.3 迭代思路)

1. 题目内容


Leetcode链接

2. 解题思路

2.1 模拟思路

题目虽然名为破冰行动 ,但实际上就是约瑟夫环问题 ,找出最后的幸存者。

出局条件清晰,就是依次报数,报到指定数的人出局,然后从下一个人开始继续报数,因此可以模拟整个过程。
约瑟夫环问题,可以通过数组模拟,也可以通过链表模拟,数组模拟的时间复杂度会高于链表------链表时间复杂度在O(n * target) , 数组时间复杂度至少为O(n * target) 。

对于此题而言,由于测试数据量较大,因此模拟思路,即数组或链表模拟,会超时。

2.1.1 数组模拟

cpp 复制代码
class Solution {
public:
    int iceBreakingGame(int num, int target) {
        // 数组实现
        vector<int> arr(num,0);
        int cnt = 0,i = 0,k = 0;
        while(cnt < num) {
            i %= num;
            if(arr[i] == 0) {
                k++;
                if(k == target) {
                    k = 0;
                    arr[i] = 1;
                    cnt++;
                }
            }
            i++;
        }
        return i - 1;
    }
};

2.1.2 链表模拟

cpp 复制代码
class Solution {
public:
    int iceBreakingGame(int num, int target) {
        // 链表实现
        list<int> l;
        for(int i = 0; i < num; i++) {
            l.push_back(i);
        }
        int k = 0;
        auto it = l.begin();
        while(l.size() > 1) {
            k++;
            if(k == target) {
                k = 0;
                it = l.erase(it);
            } else {
                it++;
            }
            if(it == l.end())
                it = l.begin();
        }
        return *it;
    }
};

2.2 递归思路

约瑟夫环问题,之所以可以用递归思路求解,本质因为不同人数下的约瑟夫环问题有关联之处

假设有N个人,那么从中去除一个人后,从下一个人开始,如果重新编号,那么最终幸存者编号与N - 1个人时情况一定相同(从编号上而言)。换言之,假设知道N - 1个人时,幸存者编号,就一定可以知道,N个人中去除一个人并重新编号后,最终幸存者的编号,而如果我们能够将N个人时,重新编号后得到的幸存者编号,还原回N个人时的原始编号,那么就得到N个人情况下,最终幸存者编号。

所以,依照上述思路,同时利用模运算的相关性质,我们最终可得出如下转移方程(该状态转移方程的起始编号为0,即N人,编号为 0 ~ N - 1;同时,报数,即target,总是从1开始计数):
F(n) = [(target - 1) % n + 1 + F(n - 1)] % n

利用模运算的性质,优化后可得:
F(n) = (target + F(n - 1)) % n

cpp 复制代码
class Solution {
public:
    int dfs(int num,int target) {
        if(num == 1)
            return 0;
        return (dfs(num - 1,target) + target) % num;
    }
    int iceBreakingGame(int num, int target) {
        return dfs(num,target);   
    }
};

2.3 迭代思路

迭代思路和递归是相同,本质就是递归和迭代间的转换,递归是自上而下的,而迭代是自下而上的。

在时间复杂度上,二者相同,均为O(n) ;但是空间复杂度,递归由于由栈开销,复杂度为O(n),迭代则为O(1)。

cpp 复制代码
class Solution {
public:
    int iceBreakingGame(int num, int target) {
        int ret = 0;
        for(int i = 2; i <= num; i++) {
            ret = (target + ret) % i;
        }
        return ret;
    }
};
相关推荐
1104.北光c°16 小时前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
仰泳的熊猫20 小时前
题目2570:蓝桥杯2020年第十一届省赛真题-成绩分析
数据结构·c++·算法·蓝桥杯
无极低码1 天前
ecGlypher新手安装分步指南(标准化流程)
人工智能·算法·自然语言处理·大模型·rag
软件算法开发1 天前
基于海象优化算法的LSTM网络模型(WOA-LSTM)的一维时间序列预测matlab仿真
算法·matlab·lstm·一维时间序列预测·woa-lstm·海象优化
superior tigre1 天前
22 括号生成
算法·深度优先
努力也学不会java1 天前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
旖-旎1 天前
二分查找(x的平方根)(4)
c++·算法·二分查找·力扣·双指针
ECT-OS-JiuHuaShan1 天前
朱梁万有递归元定理,重构《易经》
算法·重构
智者知已应修善业1 天前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机