链表:约瑟夫环

题目:

输入:一个环形单链表的头节点 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名企算法与数据结构题目最优解,左程云

原文地址:https://www.cnblogs.com/2015110615L/p/6659958.html