DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • Array

    • 数组
    • 二分查找
    • moveZeros
  • Dynamic-programming

    • 动态规划
  • 刷题指南
  • String

    • 字符串
  • bitwise-operator

    • 位运算符
  • heap
  • history

    • [1014] 最佳观光组合
    • [1022] 从根到叶的二进制数之和
    • [104] 二叉树的最大深度
    • [11] 盛最多水的容器
    • [110] 平衡二叉树
    • [1227] 飞机座位分配概率
    • [129] 求根节点到叶节点数字之和
    • [1306] 跳跃游戏 III
    • [148] 排序链表
    • 155.最小栈
    • [165] 比较版本号
    • 1763. 最长的美好子字符串
    • [1870] 准时到达的列车最小时速
    • [199] 二叉树的右视图
    • [21] 合并两个有序链表
    • 215.数组中的第 k 个最大元素
    • [2306] 公司命名
    • [234] 回文链表
    • [2516] 每种字符至少取 K 个
    • [316] 去除重复字母
    • [3171] 找到按位或最接近 K 的子数组
    • [322] 零钱兑换
    • [41] 缺失的第一个正数
    • [44] 通配符匹配
    • [494] 目标和
    • [509] 斐波那契数
    • [518] 零钱兑换 II
    • [62] 不同路径
    • [676] 实现一个魔法字典
    • 70 爬楼梯
    • [718] 最长重复子数组
    • [78] 子集
    • [82] 删除排序链表中的重复元素 II
    • [871] 最低加油次数
    • [88] 合并两个有序数组
    • [887] 鸡蛋掉落
    • 958.二叉树的完全性检验
    • [98] 验证二叉搜索树
    • [983] 最低票价
    • leetcode practice
    • 约瑟夫问题
    • 移除重复节点
  • linked-list

    • 706. 设计哈希映射
    • 链表
  • stack

    • stack
  • tree

    • Tree Traversal
    • 二叉树的最近公共祖先
    • 二叉树
    • 题目
  • leetCode 刷题
  • 回溯
  • 排序算法

约瑟夫问题

递归解法推理过程

约瑟夫问题的递归解法主要基于以下思想:

  1. 基本情况: 如果只有一个人,那么他就是最后剩下的人。
  2. 递归关系: 假设我们知道 n-1 个人时,最后剩下的人的位置,我们可以推导出 n 个人时的最后剩下的人的位置。

设 f(n, k) 表示 n 个人、每数到 k 杀掉一个人的最后剩下的人的位置(0-based)。我们可以推导出以下递归关系:

f(n,k)=(f(n−1,k)+k)%n f(n, k) = (f(n-1, k) + k) \% n f(n,k)=(f(n−1,k)+k)%n

推导过程

  1. 基础情况:

    • 当 n = 1 时,最后剩下的人位置是 0。即 f(1, k) = 0。
  2. 递归情况:

    • 假设我们知道 f(n-1, k) 的结果,即 n-1 个人时最后剩下的人位置。
    • 加上k个位置后再取模n,我们可以得到n个人时最后剩下的人的位置。

实现

根据上述推理,我们可以实现递归解法:

function lastRemaining(n, k) {
    function josephus(n, k) {
        // 基础情况
        if (n === 1) {
            return 0;
        } else {
            // 递归情况
            return (josephus(n - 1, k) + k) % n;
        }
    }
    // 调用递归函数
    return josephus(n, k);
}

详细推理过程

假设 num = 5 和 target = 3,我们逐步展示每一步的递归过程:

  1. 初始调用: lastRemaining(5, 3)

  2. 递归调用:

    • josephus(5, 3)
      • 需要 josephus(4, 3)
        • 需要 josephus(3, 3)
          • 需要 josephus(2, 3)
            • 需要 josephus(1, 3)
  3. 基础情况:

    • josephus(1, 3) = 0
  4. 返回值计算:

    • josephus(2, 3) = (0 + 3) % 2 = 1
    • josephus(3, 3) = (1 + 3) % 3 = 1
    • josephus(4, 3) = (1 + 3) % 4 = 0
    • josephus(5, 3) = (0 + 3) % 5 = 3

总结

通过递归方式,我们逐步从基础情况推导出最后的结果。每次递归调用都基于前一次的结果加上target后再取模当前人数,从而最终得到结果。

这个递归解法时间复杂度是 O(n),空间复杂度由于递归调用栈也为 O(n)。

完整代码

function lastRemaining(n, k) {
    function josephus(n, k) {
        // 基础情况
        if (n === 1) {
            return 0;
        } else {
            // 递归情况
            return (josephus(n - 1, k) + k) % n;
        }
    }
    // 调用递归函数
    return josephus(n, k);
}
Last Updated:
Contributors: rosendo
Prev
leetcode practice
Next
移除重复节点