package com.my.util;
/**
* 单向链表节点
* */
public class SingleNode {
public int value;
public SingleNode next;
public SingleNode(int data){
this.value = data;
}
}
package com.my.suanfa;
import com.my.util.SingleNode;
/**
* 环形单链表的约瑟夫问题
* 方法一:每删除一个节点就要遍历m次,共有n个节点,时间复杂度为O(n * m)
* 方法二:时间复杂度为O(N)
* */
public class Solution03 {
/**
* 方法一:每删除一个节点就要遍历m次,共有n个节点,时间复杂度为O(n * m)
* */
public SingleNode josePhusKill1(SingleNode head, int m) {
//边界条件判断
if(head == null || head.next == null || m < 1) {
return head;
}
//定义一个节点指向链表的尾节点,因为是环形链表,删除链表操作时刻在进行,所以链表的头结点和尾节点也是时刻变化的
SingleNode last = head;
//遍历链表找到初始尾节点的位置
while(last.next != head) {
last = last.next;
}
int count = 0;
//只要head != last说明环形链表中的节点数不止一个,就要继续删除操作
while(head != last) {
//因为环形链表是时刻变化的,所以每判断一个节点都要重新找到新的head和last
//只要环形链表中的节点数超过一个,那么head和last之间就永远差一个节点
//正在遍历的节点是要删除的节点
if(++count == m) {
//删除节点
last.next = head.next;
//将count重新归零
count = 0;
}else {
//正在遍历的节点不是要删除的节点,说明当前last不是真正的last,则将last指向其后继节点
last = last.next;
}
//完成一个节点的判断之后,因为last与head之间只差一个节点,因此新的head就是last.next
//head始终记录的是下一个要判断的节点
head = last.next;
}
//删除结束后head == last,说明此事链表中只剩下一个节点,此节点 就是最后剩下的节点
return last;
}
/**
* 方法二:时间复杂度为O(N)
* 假设初始节点个数为i的环最后幸存者的编号为Num(i),
* 初始节点个数为i - 1的环最后幸存者的编号为Num(i - 1)
* 1:还没有删除节点时报号A,与编号B之间的关系为:B = (A - 1) % i + 1,即报A的是编号B的节点
* 2:删除节点s前的编号old,与删除节点后的编号new各节点的编号之家呢关系为:old = (new + s - 1) % i + 1
* 报数为 m的节点将会被删除,代入两式化简后得到Num(i - 1)-->new,与Num(i)-->old的关系式只与m,i有关,为:old = (new + m - 1) % i + 1
* */
public SingleNode josephusKill2(SingleNode head, int m) {
//边界条件判断
if(head == null || head.next == head || m < 1) {
return head;
}
//定义临时节点,指向头结点,用来计算初始链表中节点的个数
SingleNode cur = head.next;
//计数器用来记录环形链表中的节点的个数
int tmp = 1;
//遍历环形链表记录计算初始节点的个数
while(cur != head) {
tmp++;
cur = cur.next;
}
//tmp记录最后存活的节点的编号
tmp = getLive(tmp, m);
while(--tmp != 0) {
//循环结束时head正好指向最后活下来的节点
head = head.next;
}
//重新将活下来的节点的后一个节点设为头结点
head.next = head;
return head;
}
/**
* 计算最后活下来的节点报的号
* 参数含义:
* i:此时环形链表中的节点的个数
* m:要删除的节点的编号
* 返回值为当前幸存者的编号
* */
public int getLive(int i, int m) {
//递归结束条件
if(i == 1) {
return i;
}
return (getLive(i - 1, m) + m - 1) % i + 1;
}
}