题目:
输入:一个环形单链表的头节点 head 和报数的值 m
返回:最后生存下来的结点,且这个节点自己组成环形单向链表,其他节点都删掉
进阶:
如果链表节点数为 N,想在时间复杂度为 O(N)时完成原问题的要求,该怎么实现?
先看看普通的解法:
1. 如果链表为空或节点数为1,或者m的值小于1,则不用调整就直接返回
2. 获取当前节点的前一个节点pre,在环形链表中遍历每一个节点,让每个节点报数,当报数达到m时,就删除当前报数的结点
3.不停删除直到环形链表只剩一个节点,过程结束
1 public class Node 2 { 3 public int data; 4 public Node next; 5 public Node(int data) 6 { 7 this.data = data; 8 } 9 } 10 11 public Node josephusKill(Node head, int m) 12 { 13 if(head == null || head.next = head || m < 1) 14 { 15 return head; 16 } 17 18 Node pre = head; 19 while(pre.next != head) 20 { 21 pre = pre.next; 22 } 23 24 int count = 0; 25 while(head != pre) 26 { 27 if(++count == m) 28 { 29 pre.next = head.next; 30 count = 0; 31 } 32 else 33 { 34 pre = pre.next; 35 } 36 head = head.next; 37 } 38 return head; 39 }
第二种方法:
假设环大小为 i 的节点编号为 old,环大小为 i-1 的每个节点编号为 new,由此得到一个递归公式: old = (new + m - 1) % i + 1;
1 public Node josephusKill(Node head, int m) 2 { 3 if(head == null || head.next = head || m < 1) 4 { 5 return head; 6 } 7 8 Node cur = head.next; 9 int len = 1; 10 while(cur != head) 11 { 12 len++; 13 cur = cur.next; 14 } 15 len = getLive(len, m); 16 while(--len != 0) 17 { 18 head = head.next; 19 } 20 head.next = head; 21 return head; 22 } 23 24 public int getLive(int i, int m) 25 { 26 if(i == 1) 27 { 28 return 1; 29 } 30 return (getLive(i-1, m) + m - 1) % i + 1; 31 }
参考资料:程序员代码面试指南 IT名企算法与数据结构题目最优解,左程云