【△重点△】剑指 Offer 62. 圆圈中最后剩下的数字——约瑟夫环问题
题目描述
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:
输入: n = 10, m = 17
输出: 2
解题思路
((n-1)个元素情况下,剩余元素的下标 + m) % n
public int lastRemaining_1(int n, int m) {
return f(n,m);
}
public int f(int n,int m){
if (n == 1)
return 0;
int x = f(n - 1,m); // 查找 有n-1个数字 的情况下,删除第m个数字 的剩余元素
return (m + x) % n; // 根据 上一轮的计算结果,计算 本轮剩余元素
}
public int lastRemaining(int n,int m){
int f = 0;
for(int i = 2;i != n + 1;++i){
f = (m + f) % i;
}
return f;
}
题目二 (环形链表的约瑟夫问题)
import java.util.*;
public class Solution {
public int ysf (int n, int m) {
// write code here
LinkedList<Integer> list = new LinkedList<>();
for (int i=1;i<=n;++i){
list.addLast(i);
}
int curr = 0;
while (list.size() > 1){
int size = list.size();
int pos = (curr-1 + m)%size;
list.remove(pos);
curr = pos % (size-1); // 若删除的是最后一个,重置curr为0
}
return list.get(0);
}
}
题目变形,不求最后一个人,求剩余m-1个人的编号
第一步创建链表存1~n个数字,每次循环装数字i,指针后移,最后指向头节点形成环p.next=head
第二步while循环,数到第m个删除就行了,pre.next = p .next 再指针后移 p =pre.next
import java.util.*;
public class Solution {
public ListNode newList(int nn) {
ListNode head = new ListNode(1);
ListNode p = head;
for(int i = 2; i <= nn; i++) {
ListNode node = new ListNode(i);
p.next = node;
p = node;
}
p.next = head;
return head;
}
public int ysf(int n, int m) {
ListNode head = newList(n);
ListNode p = head;
ListNode tmp = null;//单链表删除p,必须用辅助节点temp来存p前一个节点pre
while(p.next != p) {
for(int i = 1; i < m; i++) {
tmp = p;//更新前一个节点
p = p.next;
}
tmp.next = p.next;//删除p
p = tmp.next;//指针后移
}
return p.val;
}
}