据说著名犹太历史学家 Josephus 有过以下故事:在罗马人占领乔塔帕特后,39 个犹太人与 Josephus 及他的朋友躲到一个洞中,39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一种自杀方式,41 个人排成一个圆圈,由第 1 个人开始报数,报数到 3 的人就自杀,然后再由下一个人重新报 1,报数到 3 的人再自杀,这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表得出最终存活的人的编号。
一行两个整数 n 和 m, n 表示环形链表的长度, m 表示每次报数到 m 就自杀。
输出最后存活下来的人编号(编号从1开始到n)
5 2
3
import java.util.*; class node{ int val; node next; public node(){}; public node(int val) { this.val = val; } } public class Code61_yuesefuProblem { public static void main(String[] args) { node ans = new node(); node index = ans; Scanner in = new Scanner(System.in); node mynode = new node(); int n = in.nextInt(); int m=in.nextInt(); for (int i = 1; i <= n; i++) { node temp = new node(i); index.next = temp; index = index.next; } index.next = ans; int ch=n; int count=1; node p=ans; node q=ans.next; while(ch!=1) { if (count == m &&q.val!=0) { //System.out.println("所删除的节点"+q.val); q = q.next; p.next = q; count = 1; ch--; } else if (count != m &&q.val!=0) { p = p.next; q = q.next; count++; } else{ p=p.next; q=q.next; } } node test=ans.next; while(true) { if(test.val!=0){ System.out.println(test.val); break; } test=test.next; } } }
大概思路 1.就是循环赋值然后附完值后让指针指向头形成单循环链表 2.然后删除用的基本操作遇到对应的删除节点时前指针先走一步然后后指针指向他删除该指针并且计数器count置为1,如果不是的话就俩指针各走一步然后count++ 3.对了我加了一个q.val!=0是因为我创建的链表是带头节点的方便操作但是头节点不参与循环所以到他的时候基数器不参与任何变化
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; class ListNode { public int val; public ListNode next; public ListNode(int val) { this.val = val; } } public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] params = br.readLine().split(" "); int n = Integer.parseInt(params[0]), m = Integer.parseInt(params[1]); ListNode head = new ListNode(1); ListNode cur = head; for(int i = 2; i <= n; i++){ cur.next = new ListNode(i); cur = cur.next; } int live = 1; // 长度为1时,剩下节点的编号 // 倒推得到长度为n时它的编号 for(int i = 2; i <= n; i++) live = (live + m - 1) % i + 1; cur = head; for(int i = 1; i < live; i++) cur = cur.next; System.out.println(cur.val); } }直接用链表模拟的话每报数m次就删除一个节点,一共要删除n-1个节点,因此时间复杂度为O(mn);而用公式倒推的话需要调用n-1次时间复杂度为O(1)的公式,整体时间复杂度为O(n)。