约瑟夫问题2

问题描述:约瑟夫问题是一个著名的趣题。这里我们稍稍修改一下规则。有n个人站成一列。并从头到尾给他们编号,第一个人编号为1。然后从头开始报数,第一轮依次报1,2,1,2…然后报到2的人出局。接着第二轮再从上一轮最后一个报数的人开始依次报1,2,3,1,2,3…报到2,3的人出局。以此类推直到剩下以后一个人。现在需要求的即是这个人的编号。
给定一个int n,代表游戏的人数。请返回最后一个人的编号

直接看代码注释:

import java.util.*;


public class Joseoh{
	public int getResult(int n){
		//创建链表(底层双向链表实现),然后将n个数依次输入
		LinkedList<Integer> list = new LinkedList<Integer>();
		for(int i = 1; i <= n; i++){
			list.add(i);
		}
		//设置初始长度
		int k = 2;
		//遍历链表,直到只剩一个元素时退出
		while(list.size()>1){
			//重点:将报数过程中与k取余值不等于1的值设为-1
			for(int i = 0;i<list.size();i++){
				list.set(i,-1);
			}
			
			//长度+1
			k++;
			//迭代器用于遍历链表
			Iterator<Integer> iter = list.iterator();
			while(iter.hasNext()){
				if(iter.next()==-1){
					iter.remove();
				}
			}
			list.addFirst(list.remove(list.size()-1));
		}
		//返回链表仅剩的一个值
		return list.get(0);
	}
}
### 约瑟夫问题的 Java 实现 #### 1. 使用 List 模拟删除 可以通过 `ArrayList` 来模拟约瑟夫环的过程。每次找到目标位置后,移除该元素并继续查找下一个目标。 ```java import java.util.ArrayList; import java.util.List; public class JosephusProblem { public static void main(String[] args) { int n = 7; // 人数 int m = 3; // 数到m的人出列 List<Integer> list = new ArrayList<>(); for (int i = 1; i <= n; i++) { list.add(i); } int index = 0; while (!list.isEmpty()) { index = (index + m - 1) % list.size(); System.out.print(list.remove(index) + " "); } } } ``` 这种方法的时间复杂度较高,因为频繁调用 `remove()` 方法会带来额外开销[^1]。 --- #### 2. 动态规划 + 循环 另一种更高效的解决方法是利用动态规划的思想来计算最后剩下的那个人的位置。核心公式如下: \[ f(n, m) = \begin{cases} 0 & ,n=1 \\ (f(n-1,m)+m)\%n &,n>1 \end{cases} \] 其中 \(f(n, m)\) 表示共有 \(n\) 个人时,最终剩下人的编号。 ```java public class JosephusDynamicProgramming { public static void main(String[] args) { int n = 7; // 人数 int m = 3; // 数到m的人出列 int lastPerson = findLastRemaining(n, m); System.out.println(lastPerson); // 输出最后一个留下的人的编号 } private static int findLastRemaining(int n, int m) { int result = 0; for (int i = 2; i <= n; i++) { result = (result + m) % i; } return result + 1; // 编号从1开始 } } ``` 此方法仅需一次遍历即可得出结果,时间复杂度为 O(n)[^4]。 --- #### 3. 动态规划 + 递归 还可以采用递归来实现上述逻辑,不过需要注意栈溢出的风险。 ```java public class JosephusRecursive { public static void main(String[] args) { int n = 7; // 人数 int m = 3; // 数到m的人出列 int lastPerson = findLastRemaining(n, m); System.out.println(lastPerson); // 输出最后一个留下的人的编号 } private static int findLastRemaining(int n, int m) { if (n == 1) { return 0; } else { return (findLastRemaining(n - 1, m) + m) % n; } } } ``` 尽管递归版本简洁明了,但在大规模输入下可能会引发性能问题。 --- ### 结论 以上展示了三种不同的方式用于求解约瑟夫问题:基于列表的操作、动态规划以及递归。每种方法各有优劣,在实际开发过程中可根据具体需求选择合适的方案[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值