【详解】使用Java解决约瑟夫环问题

举报
皮牙子抓饭 发表于 2026/03/20 10:28:08 2026/03/20
【摘要】 使用Java解决约瑟夫环问题简介约瑟夫环问题是一个经典的数学问题,描述了n个人围成一圈,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。这个问题可以通过多种方法解决,本文将介绍一种基于数学公式的高效解法,并提供相应的Java实现。数学公式解法约瑟夫环问题可以通过递推公式来求解,其递推公式如下:\[ f(n, m) = \begin{cases} 0 ...

使用Java解决约瑟夫环问题

简介

约瑟夫环问题是一个经典的数学问题,描述了n个人围成一圈,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。这个问题可以通过多种方法解决,本文将介绍一种基于数学公式的高效解法,并提供相应的Java实现。

数学公式解法

约瑟夫环问题可以通过递推公式来求解,其递推公式如下:

\[ f(n, m) = \begin{cases} 0 & \text{if } n = 1 \\ (f(n-1, m) + m) \mod n & \text{if } n > 1 \end{cases} \]

其中:

  • \( f(n, m) \) 表示n个人报数m时最后留下的人的位置。
  • 初始条件是 \( f(1, m) = 0 \),表示只有一个人时,最后留下的人是第0号(从0开始计数)。

通过这个递推公式,我们可以逐步计算出最后留下的人的位置。

Java实现

下面是使用Java实现上述递推公式的代码:

public class JosephusProblem {
    /**
     * 计算约瑟夫环问题中最后留下的人的位置
     *
     * @param n 人数
     * @param m 报数的数字
     * @return 最后留下的人的位置(从0开始计数)
     */
    public static int findLastPerson(int n, int m) {
        if (n == 1) {
            return 0;
        }
        return (findLastPerson(n - 1, m) + m) % n;
    }

    public static void main(String[] args) {
        int n = 10; // 人数
        int m = 3;  // 报数的数字
        int lastPerson = findLastPerson(n, m);
        System.out.println("最后留下的人是原来的第 " + (lastPerson + 1) + " 号");
    }
}

代码解释

  1. findLastPerson 方法:
  • 参数 ​​n​​ 表示总人数。
  • 参数 ​​m​​ 表示报数的数字。
  • 如果 ​​n​​ 等于1,返回0,因为只有一个人时,最后留下的人是第0号。
  • 否则,递归调用 ​​findLastPerson(n - 1, m)​​ 并计算 ​​(f(n-1, m) + m) % n​​。
  1. main 方法:
  • 定义人数 ​​n​​ 和报数的数字 ​​m​​。
  • 调用 ​​findLastPerson​​ 方法计算最后留下的人的位置。
  • 输出结果,注意位置是从0开始计数的,所以输出时加1。

时间复杂度

该算法的时间复杂度为 \( O(n) \),因为每次递归调用都会减少一个元素,直到 ​​n​​ 减少到1为止。空间复杂度为 \( O(n) \),因为递归调用会占用栈空间。


约瑟夫环问题是一个经典的算法问题,可以通过多种方式解决,包括递归、迭代和数学公式。下面我将提供一个使用Java实现的解决方案,该方案基于数学公式,时间复杂度为O(1)。

数学公式解法

对于约瑟夫环问题,可以使用以下递推公式来解决:

\[ f(n, m) = (f(n-1, m) + m) \mod n \]

其中:

  • \( n \) 是人数。
  • \( m \) 是报数的步长(在这个问题中,m=3)。
  • \( f(n, m) \) 表示最后留下的人的编号(从0开始计数)。

最终结果需要转换为从1开始计数的编号。

Java 实现

public class JosephusProblem {

    // 计算最后留下的人的编号(从1开始计数)
    public static int findLastPerson(int n, int m) {
        // 初始化,当只有一个人时,最后留下的人是0号
        int lastPerson = 0;

        // 从2人开始,逐步增加到n人
        for (int i = 2; i <= n; i++) {
            // 根据递推公式计算
            lastPerson = (lastPerson + m) % i;
        }

        // 转换为从1开始计数的编号
        return lastPerson + 1;
    }

    public static void main(String[] args) {
        int n = 10; // 人数
        int m = 3;  // 报数的步长

        int result = findLastPerson(n, m);
        System.out.println("最后留下的人是原来的第 " + result + " 号");
    }
}



解释

  1. 初始化:当只有一个人时,最后留下的人是0号(从0开始计数)。
  2. 递推计算:从2人开始,逐步增加到n人,每次根据递推公式计算当前人数下的最后留下的人的编号。
  3. 结果转换:最后的结果是从0开始计数的编号,需要加1转换为从1开始计数的编号。

示例运行

假设 ​​n = 10​​,​​m = 3​​,运行上述代码会输出:

最后留下的人是原来的第 4 号

这意味着在10个人围成一圈,从1到3报数的情况下,最后留下的人是原来的第4号。约瑟夫环问题是一个经典的递归问题,可以通过多种方式解决,包括直接模拟、递归和数学公式。这里我们使用Java语言来实现一个高效的解决方案,采用数学公式的方法,因为这种方法的时间复杂度为O(n),非常高效。

约瑟夫环问题的数学解法

对于约瑟夫环问题,有一个著名的数学公式可以用来快速求解:

\[ f(n, m) = (f(n-1, m) + m) \% n \]

其中:

  • \( n \) 是人数。
  • \( m \) 是每次报数的数字(在这个问题中是3)。
  • \( f(n, m) \) 表示从 \( n \) 个人中,每次报数到 \( m \) 的人出圈,最后剩下的人的位置(从0开始编号)。

初始条件是 \( f(1, m) = 0 \),即只有1个人时,最后剩下的人就是这个人自己,位置为0。

Java代码实现

public class JosephusProblem {

    public static int findLastPerson(int n, int m) {
        // 初始条件:只有1个人时,最后剩下的人的位置是0
        int pos = 0;

        // 动态计算每个人出圈后,最后剩下的人的位置
        for (int i = 2; i <= n; i++) {
            pos = (pos + m) % i;
        }

        // 返回最后剩下的人的位置(从1开始编号)
        return pos + 1;
    }

    public static void main(String[] args) {
        int n = 5; // 人数
        int m = 3; // 报数的数字

        int lastPerson = findLastPerson(n, m);
        System.out.println("最后留下的是原来第 " + lastPerson + " 号的那位。");
    }
}

代码解释

  1. findLastPerson 方法:
  • 参数 ​​n​​ 表示人数。
  • 参数 ​​m​​ 表示每次报数的数字。
  • 初始化 ​​pos​​ 为0,表示只有1个人时,最后剩下的人的位置是0。
  • 使用一个循环从2到n,逐步计算每轮出圈后,最后剩下的人的位置。
  • 最后返回 ​​pos + 1​​,因为题目要求从1开始编号。
  1. main 方法:
  • 定义人数 ​​n​​ 和报数的数字 ​​m​​。
  • 调用 ​​findLastPerson​​ 方法计算最后剩下的人的位置。
  • 打印结果。

示例

假设 ​​n = 5​​,​​m = 3​​,则输出应该是:

最后留下的是原来第 4 号的那位。

这个方法的时间复杂度为O(n),非常高效,适用于较大的输入规模。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。