链表【基础算法题】

题目一

 代码实现

 1 package class_03;
 2 
 3 public class Code_07_ReverseList {
 4 
 5     public static class Node {
 6         public int value;
 7         public Node next;
 8 
 9         public Node(int data) {
10             this.value = data;
11         }
12     }
13 
14     public static Node reverseList(Node head) {
15         Node pre = null;
16         Node next = null;
17         while (head != null) {
18             next = head.next;
19             head.next = pre;
20             pre = head;
21             head = next;
22         }
23         return pre;
24     }
25 
26     public static class DoubleNode {
27         public int value;
28         public DoubleNode last;
29         public DoubleNode next;
30 
31         public DoubleNode(int data) {
32             this.value = data;
33         }
34     }
35 
36     public static DoubleNode reverseList(DoubleNode head) {
37         DoubleNode pre = null;
38         DoubleNode next = null;
39         while (head != null) {
40             next = head.next;
41             head.next = pre;
42             head.last = next;
43             pre = head;
44             head = next;
45         }
46         return pre;
47     }
48 
49     public static void printLinkedList(Node head) {
50         System.out.print("Linked List: ");
51         while (head != null) {
52             System.out.print(head.value + " ");
53             head = head.next;
54         }
55         System.out.println();
56     }
57 
58     public static void printDoubleLinkedList(DoubleNode head) {
59         System.out.print("Double Linked List: ");
60         DoubleNode end = null;
61         while (head != null) {
62             System.out.print(head.value + " ");
63             end = head;
64             head = head.next;
65         }
66         System.out.print("| ");
67         while (end != null) {
68             System.out.print(end.value + " ");
69             end = end.last;
70         }
71         System.out.println();
72     }
73 
74     public static void main(String[] args) {
75         Node head1 = new Node(1);
76         head1.next = new Node(2);
77         head1.next.next = new Node(3);
78         printLinkedList(head1);
79         head1 = reverseList(head1);
80         printLinkedList(head1);
81 
82         DoubleNode head2 = new DoubleNode(1);
83         head2.next = new DoubleNode(2);
84         head2.next.last = head2;
85         head2.next.next = new DoubleNode(3);
86         head2.next.next.last = head2.next;
87         head2.next.next.next = new DoubleNode(4);
88         head2.next.next.next.last = head2.next.next;
89         printDoubleLinkedList(head2);
90         printDoubleLinkedList(reverseList(head2));
91 
92     }
93 
94

题目二

 思路

有点类似归并排序外排的方式, 从小的开始比对,如果都相等就打印。

 代码实现

 1 package class_03;
 2 
 3 public class Code_10_PrintCommonPart {
 4 
 5     public static class Node {
 6         public int value;
 7         public Node next;
 8         public Node(int data) {
 9             this.value = data;
10         }
11     }
12 
13     public static void printCommonPart(Node head1, Node head2) {
14         System.out.print("Common Part: ");
15         while (head1 != null && head2 != null) {
16             if (head1.value < head2.value) {
17                 head1 = head1.next;
18             } else if (head1.value > head2.value) {
19                 head2 = head2.next;
20             } else {
21                 System.out.print(head1.value + " ");
22                 head1 = head1.next;
23                 head2 = head2.next;
24             }
25         }
26         System.out.println();
27     }
28 
29     public static void printLinkedList(Node node) {
30         System.out.print("Linked List: ");
31         while (node != null) {
32             System.out.print(node.value + " ");
33             node = node.next;
34         }
35         System.out.println();
36     }
37 
38     public static void main(String[] args) {
39         Node node1 = new Node(2);
40         node1.next = new Node(3);
41         node1.next.next = new Node(5);
42         node1.next.next.next = new Node(6);
43 
44         Node node2 = new Node(1);
45         node2.next = new Node(2);
46         node2.next.next = new Node(5);
47         node2.next.next.next = new Node(7);
48         node2.next.next.next.next = new Node(8);
49 
50         printLinkedList(node1);
51         printLinkedList(node2);
52         printCommonPart(node1, node2);
53 
54     }
55 
56 }

题目三

链表问题在笔试和面试上的要求不一样,笔试中一般都考虑最快的方式,不用考虑空间,面试中除了考虑时间复杂度外还要考虑空间复杂度。

 思路

①准备一个栈,遍历的过程中,把所有的节点压入栈中,第二次遍历,每遍历到一个数,就从栈中弹出一个数,每一步比对值都相等,就是回文结构;有任何一个不相等就不是回文结构。

②准备一个栈,一个慢指针,一个快指针,第一次遍历的过程中,快指针一次走2个节点,慢指针一次走一个节点,当快指针到达最后一个节点时,把慢指针所指向的节点之后的节点依次压入栈中,第二次遍历,每遍历到一个数,就从栈中弹出一个数,直到把栈中的数都比对完,每一步比对值都相等,就是回文结构;有任何一个不相等就不是回文结构。相当于把右边的一半折过去,比对是否相等。

 

③在②的基础上改进,不准备辅助数组,还是一个慢指针一个快指针,快指针到终点,慢指针在中点时,将右半边的链表逆序。

👉👉

 从两边开始依次往中间走,每走一个比对一次,直到两边有任何一边走到了中点的节点(怎么判断?这个节点的next为null,则代表它是那个中间的节点),如果全部相等就是回文结构,有一步不等就不是回文结构。

返回完结果后,把后半段的结构恢复成原来的样子。

 注意:奇数个节点,要保证慢指针走到最中间的节点位置,偶数个节点要保证慢指针走到中间两个节点的中前面那个节点的位置。

代码实现

  1 package class_03;
  2 
  3 import java.util.Stack;
  4 
  5 public class Code_11_IsPalindromeList {
  6 
  7     public static class Node {
  8         public int value;
  9         public Node next;
 10 
 11         public Node(int data) {
 12             this.value = data;
 13         }
 14     }
 15 
 16     // need n extra space
 17     public static boolean isPalindrome1(Node head) {
 18         Stack<Node> stack = new Stack<Node>();
 19         Node cur = head;
 20         while (cur != null) {
 21             stack.push(cur);
 22             cur = cur.next;
 23         }
 24         while (head != null) {
 25             if (head.value != stack.pop().value) {
 26                 return false;
 27             }
 28             head = head.next;
 29         }
 30         return true;
 31     }
 32 
 33     // need n/2 extra space
 34     public static boolean isPalindrome2(Node head) {
 35         if (head == null || head.next == null) {
 36             return true;
 37         }
 38         Node right = head.next;
 39         Node cur = head;
 40         while (cur.next != null && cur.next.next != null) {
 41             right = right.next;
 42             cur = cur.next.next;
 43         }
 44         Stack<Node> stack = new Stack<Node>();
 45         while (right != null) {
 46             stack.push(right);
 47             right = right.next;
 48         }
 49         while (!stack.isEmpty()) {
 50             if (head.value != stack.pop().value) {
 51                 return false;
 52             }
 53             head = head.next;
 54         }
 55         return true;
 56     }
 57 
 58     // need O(1) extra space
 59     public static boolean isPalindrome3(Node head) {
 60         if (head == null || head.next == null) {
 61             return true;
 62         }
 63         Node n1 = head;
 64         Node n2 = head;
 65         while (n2.next != null && n2.next.next != null) { // find mid node
 66             n1 = n1.next; // n1 -> mid
 67             n2 = n2.next.next; // n2 -> end
 68         }
 69         n2 = n1.next; // n2 -> right part first node
 70         n1.next = null; // mid.next -> null
 71         Node n3 = null;
 72         while (n2 != null) { // right part convert
 73             n3 = n2.next; // n3 -> save next node
 74             n2.next = n1; // next of right node convert
 75             n1 = n2; // n1 move
 76             n2 = n3; // n2 move
 77         }
 78         n3 = n1; // n3 -> save last node
 79         n2 = head;// n2 -> left first node
 80         boolean res = true;
 81         while (n1 != null && n2 != null) { // check palindrome
 82             if (n1.value != n2.value) {
 83                 res = false;
 84                 break;
 85             }
 86             n1 = n1.next; // left to mid
 87             n2 = n2.next; // right to mid
 88         }
 89         n1 = n3.next;
 90         n3.next = null;
 91         while (n1 != null) { // recover list
 92             n2 = n1.next;
 93             n1.next = n3;
 94             n3 = n1;
 95             n1 = n2;
 96         }
 97         return res;
 98     }
 99 
100     public static void printLinkedList(Node node) {
101         System.out.print("Linked List: ");
102         while (node != null) {
103             System.out.print(node.value + " ");
104             node = node.next;
105         }
106         System.out.println();
107     }
108 
109     public static void main(String[] args) {
110 
111         Node head = null;
112         printLinkedList(head);
113         System.out.print(isPalindrome1(head) + " | ");
114         System.out.print(isPalindrome2(head) + " | ");
115         System.out.println(isPalindrome3(head) + " | ");
116         printLinkedList(head);
117         System.out.println("=========================");
118 
119         head = new Node(1);
120         printLinkedList(head);
121         System.out.print(isPalindrome1(head) + " | ");
122         System.out.print(isPalindrome2(head) + " | ");
123         System.out.println(isPalindrome3(head) + " | ");
124         printLinkedList(head);
125         System.out.println("=========================");
126 
127         head = new Node(1);
128         head.next = new Node(2);
129         printLinkedList(head);
130         System.out.print(isPalindrome1(head) + " | ");
131         System.out.print(isPalindrome2(head) + " | ");
132         System.out.println(isPalindrome3(head) + " | ");
133         printLinkedList(head);
134         System.out.println("=========================");
135 
136         head = new Node(1);
137         head.next = new Node(1);
138         printLinkedList(head);
139         System.out.print(isPalindrome1(head) + " | ");
140         System.out.print(isPalindrome2(head) + " | ");
141         System.out.println(isPalindrome3(head) + " | ");
142         printLinkedList(head);
143         System.out.println("=========================");
144 
145         head = new Node(1);
146         head.next = new Node(2);
147         head.next.next = new Node(3);
148         printLinkedList(head);
149         System.out.print(isPalindrome1(head) + " | ");
150         System.out.print(isPalindrome2(head) + " | ");
151         System.out.println(isPalindrome3(head) + " | ");
152         printLinkedList(head);
153         System.out.println("=========================");
154 
155         head = new Node(1);
156         head.next = new Node(2);
157         head.next.next = new Node(1);
158         printLinkedList(head);
159         System.out.print(isPalindrome1(head) + " | ");
160         System.out.print(isPalindrome2(head) + " | ");
161         System.out.println(isPalindrome3(head) + " | ");
162         printLinkedList(head);
163         System.out.println("=========================");
164 
165         head = new Node(1);
166         head.next = new Node(2);
167         head.next.next = new Node(3);
168         head.next.next.next = new Node(1);
169         printLinkedList(head);
170         System.out.print(isPalindrome1(head) + " | ");
171         System.out.print(isPalindrome2(head) + " | ");
172         System.out.println(isPalindrome3(head) + " | ");
173         printLinkedList(head);
174         System.out.println("=========================");
175 
176         head = new Node(1);
177         head.next = new Node(2);
178         head.next.next = new Node(2);
179         head.next.next.next = new Node(1);
180         printLinkedList(head);
181         System.out.print(isPalindrome1(head) + " | ");
182         System.out.print(isPalindrome2(head) + " | ");
183         System.out.println(isPalindrome3(head) + " | ");
184         printLinkedList(head);
185         System.out.println("=========================");
186 
187         head = new Node(1);
188         head.next = new Node(2);
189         head.next.next = new Node(3);
190         head.next.next.next = new Node(2);
191         head.next.next.next.next = new Node(1);
192         printLinkedList(head);
193         System.out.print(isPalindrome1(head) + " | ");
194         System.out.print(isPalindrome2(head) + " | ");
195         System.out.println(isPalindrome3(head) + " | ");
196         printLinkedList(head);
197         System.out.println("=========================");
198 
199     }
200 
201 }

题目四

 思路

笔试:将链表中的数依次放入数组中,用荷兰国旗问题的方法来解决,之后再把数组中各个元素重新链接,恢复成链表结构。

进阶:荷兰国旗问题的方法保证不了稳定性,且因为需要一个辅助数组,额外空间复杂度得O(n)。

           引入6个变量,less,equal,more都是节点类型,初始都为null。它们三个“类型”每个“类型”还各需要一个变量来链接对应“类型”的链表,less-end、equal-end、more-end。

   相当于把一个大的链表拆成3种小链表,再把三种小链表合成一个大链表。

   先遍历一下链表,找到第一个小于num的节点,让less和less-end等于该节点;找到第一个大于num的节点,让more和more-end等于该节点;找到第一个等于num的节点,让equal和equal-end等于该节点;

   再遍历一次链表,找到小于num的节点,先判断是不是less,如果是不用管,如果不是,将这个节点挂在less-end的next上;equal和more也一样。直到整个链表遍历完成。

   最后将三个链表整合为一个链表。less-end和equal相连,equal-end和more相连。其中,还要考虑某种链表没有节点的情况。

            

 代码实现

  1 package class_03;
  2 
  3 public class Code_12_SmallerEqualBigger {
  4 
  5     public static class Node {
  6         public int value;
  7         public Node next;
  8 
  9         public Node(int data) {
 10             this.value = data;
 11         }
 12     }
 13 
 14     public static Node listPartition1(Node head, int pivot) {
 15         if (head == null) {
 16             return head;
 17         }
 18         Node cur = head;
 19         int i = 0;
 20         while (cur != null) {
 21             i++;
 22             cur = cur.next;
 23         }
 24         Node[] nodeArr = new Node[i];
 25         i = 0;
 26         cur = head;
 27         for (i = 0; i != nodeArr.length; i++) {
 28             nodeArr[i] = cur;
 29             cur = cur.next;
 30         }
 31         arrPartition(nodeArr, pivot);
 32         for (i = 1; i != nodeArr.length; i++) {
 33             nodeArr[i - 1].next = nodeArr[i];
 34         }
 35         nodeArr[i - 1].next = null;
 36         return nodeArr[0];
 37     }
 38 
 39     public static void arrPartition(Node[] nodeArr, int pivot) {
 40         int small = -1;
 41         int big = nodeArr.length;
 42         int index = 0;
 43         while (index != big) {
 44             if (nodeArr[index].value < pivot) {
 45                 swap(nodeArr, ++small, index++);
 46             } else if (nodeArr[index].value == pivot) {
 47                 index++;
 48             } else {
 49                 swap(nodeArr, --big, index);
 50             }
 51         }
 52     }
 53 
 54     public static void swap(Node[] nodeArr, int a, int b) {
 55         Node tmp = nodeArr[a];
 56         nodeArr[a] = nodeArr[b];
 57         nodeArr[b] = tmp;
 58     }
 59 
 60     public static Node listPartition2(Node head, int pivot) {
 61         Node sH = null; // small head
 62         Node sT = null; // small tail
 63         Node eH = null; // equal head
 64         Node eT = null; // equal tail
 65         Node bH = null; // big head
 66         Node bT = null; // big tail
 67         Node next = null; // save next node
 68         // every node distributed to three lists
 69         while (head != null) {
 70             next = head.next;
 71             head.next = null;
 72             if (head.value < pivot) {
 73                 if (sH == null) {
 74                     sH = head;
 75                     sT = head;
 76                 } else {
 77                     sT.next = head;
 78                     sT = head;
 79                 }
 80             } else if (head.value == pivot) {
 81                 if (eH == null) {
 82                     eH = head;
 83                     eT = head;
 84                 } else {
 85                     eT.next = head;
 86                     eT = head;
 87                 }
 88             } else {
 89                 if (bH == null) {
 90                     bH = head;
 91                     bT = head;
 92                 } else {
 93                     bT.next = head;
 94                     bT = head;
 95                 }
 96             }
 97             head = next;
 98         }
 99         // small and equal reconnect
100         if (sT != null) {
101             sT.next = eH;
102             eT = eT == null ? sT : eT;
103         }
104         // all reconnect
105         if (eT != null) {
106             eT.next = bH;
107         }
108         return sH != null ? sH : eH != null ? eH : bH;
109     }
110 
111     public static void printLinkedList(Node node) {
112         System.out.print("Linked List: ");
113         while (node != null) {
114             System.out.print(node.value + " ");
115             node = node.next;
116         }
117         System.out.println();
118     }
119 
120     public static void main(String[] args) {
121         Node head1 = new Node(7);
122         head1.next = new Node(9);
123         head1.next.next = new Node(1);
124         head1.next.next.next = new Node(8);
125         head1.next.next.next.next = new Node(5);
126         head1.next.next.next.next.next = new Node(2);
127         head1.next.next.next.next.next.next = new Node(5);
128         printLinkedList(head1);
129         // head1 = listPartition1(head1, 4);
130         head1 = listPartition2(head1, 5);
131         printLinkedList(head1);
132 
133     }
134 
135 }

题目五

简而言之就是,一个节点不光有next指针,还有一个random指针,可能指向链表中的任意一个节点,也可能指向null。

不要动原结构,返回一个与原结构一样的副本,也是node类型。

 思路

方法一:利用哈希表

哈希表:

插入,查询的时间复杂度都是O(1),与数据量没关系。空间复杂度O(n)

第一次遍历,

准备一个哈希表,存放原结构和原结构副本的对应关系,key是原结构的某个节点,value是它的副本。

 第二次遍历,

可以通过哈希表找到原结构对应的副本,但这个副本的next和random指针都是指向null。

我们可以通过①的next找到②,通过哈希表找到②的副本②‘,这时设置①的副本①’的next为②的副本②‘。

我们可以通过①的random找到③,通过哈希表找到③的副本③‘,这时设置①的副本①’的random为③的副本③‘。

·····以此类推,

直到把所有节点都遍历完毕,就完成了对原结构的深度拷贝。

方法二:不使用哈希表

第一次遍历节点,

让①的next指向①的副本①’,①的副本①’的next指向②,②的next指向②‘,②’的next指向③,③的next指向③‘,③’的next指向null。

 第二次遍历,

拿出①和①‘,可以通过①的random找到③,通过③的next找到③’,让①的random指针指向③‘。

同理···依次类推,把所有节点的random都设置完毕。

最后,分离next指针的指向

代码实现

  1 package class_03;
  2 
  3 import java.util.HashMap;
  4 
  5 public class Code_13_CopyListWithRandom {
  6 
  7     public static class Node {
  8         public int value;
  9         public Node next;
 10         public Node rand;
 11 
 12         public Node(int data) {
 13             this.value = data;
 14         }
 15     }
 16 
 17     public static Node copyListWithRand1(Node head) {
 18         HashMap<Node, Node> map = new HashMap<Node, Node>();
 19         Node cur = head;
 20         while (cur != null) {
 21             map.put(cur, new Node(cur.value));
 22             cur = cur.next;
 23         }
 24         cur = head;
 25         while (cur != null) {
 26             map.get(cur).next = map.get(cur.next);
 27             map.get(cur).rand = map.get(cur.rand);
 28             cur = cur.next;
 29         }
 30         return map.get(head);
 31     }
 32 
 33     public static Node copyListWithRand2(Node head) {
 34         if (head == null) {
 35             return null;
 36         }
 37         Node cur = head;
 38         Node next = null;
 39         // copy node and link to every node
 40         while (cur != null) {
 41             next = cur.next;
 42             cur.next = new Node(cur.value);
 43             cur.next.next = next;
 44             cur = next;
 45         }
 46         cur = head;
 47         Node curCopy = null;
 48         // set copy node rand
 49         while (cur != null) {
 50             next = cur.next.next;
 51             curCopy = cur.next;
 52             curCopy.rand = cur.rand != null ? cur.rand.next : null;
 53             cur = next;
 54         }
 55         Node res = head.next;
 56         cur = head;
 57         // split
 58         while (cur != null) {
 59             next = cur.next.next;
 60             curCopy = cur.next;
 61             cur.next = next;
 62             curCopy.next = next != null ? next.next : null;
 63             cur = next;
 64         }
 65         return res;
 66     }
 67 
 68     public static void printRandLinkedList(Node head) {
 69         Node cur = head;
 70         System.out.print("order: ");
 71         while (cur != null) {
 72             System.out.print(cur.value + " ");
 73             cur = cur.next;
 74         }
 75         System.out.println();
 76         cur = head;
 77         System.out.print("rand:  ");
 78         while (cur != null) {
 79             System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
 80             cur = cur.next;
 81         }
 82         System.out.println();
 83     }
 84 
 85     public static void main(String[] args) {
 86         Node head = null;
 87         Node res1 = null;
 88         Node res2 = null;
 89         printRandLinkedList(head);
 90         res1 = copyListWithRand1(head);
 91         printRandLinkedList(res1);
 92         res2 = copyListWithRand2(head);
 93         printRandLinkedList(res2);
 94         printRandLinkedList(head);
 95         System.out.println("=========================");
 96 
 97         head = new Node(1);
 98         head.next = new Node(2);
 99         head.next.next = new Node(3);
100         head.next.next.next = new Node(4);
101         head.next.next.next.next = new Node(5);
102         head.next.next.next.next.next = new Node(6);
103 
104         head.rand = head.next.next.next.next.next; // 1 -> 6
105         head.next.rand = head.next.next.next.next.next; // 2 -> 6
106         head.next.next.rand = head.next.next.next.next; // 3 -> 5
107         head.next.next.next.rand = head.next.next; // 4 -> 3
108         head.next.next.next.next.rand = null; // 5 -> null
109         head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4
110 
111         printRandLinkedList(head);
112         res1 = copyListWithRand1(head);
113         printRandLinkedList(res1);
114         res2 = copyListWithRand2(head);
115         printRandLinkedList(res2);
116         printRandLinkedList(head);
117         System.out.println("=========================");
118 
119     }
120 
121 }

题目六(难)

 思路

怎么判断一个单链表有环还是无环?

进阶:如果有环,返回第一个入环的节点,如果无环,返回null。

答:

方法一:用哈希表。

hashMap结构,有key和对应的value,能获取哈希表中是否有这个key,也可以设置或查询某个key的value。

hashSet结构,不用管key的value,只要能获取哈希表中是否有这个key即可。

从head开始遍历链表,放入哈希表中,当发现某个节点在哈希表中已经记录过时,则表明该链表是有环的,且该节点是第一个入环的节点。当遍历到最后,最后一个节点next指针指向null,表示无环。

方法二:不用哈希表。

准备两个指针,一个快指针一个慢指针,快指针一次走两步,慢指针一次走一步。

如果快指针在走的过程中遇到null了,直接返回无环。

如果有环,快指针一定会和慢指针在环上相遇。

 👉  👉  👉  👉  👉 

 相遇的时刻,快指针回到开头,由一次走两步改为一次走一步,快指针和慢指针一定会在第一个入环节点相遇。

 👉 

怎么判断两个无环单链表的第一个相交节点?

一个无环单链表和一个有环单链表不可能相交!要么两个都是无环,要么两个都是有环。

上一个问题我们可以得到一个链表是否有环,用loop来记录,如果为null代表无环,如果不为null则是无环,且第一个入环的节点就是loop。

方法一:用哈希表。

把链表1遍历放入哈希表中,再遍历链表2,看是否有节点出现在哈希表中过,第一个在的就是第一个相交的节点,如果到最后都没有,就是不相交的。

方法二:不用哈希表。

先遍历链表1,统计链表1的长度len1以及拿到链表1的最后一个节点end1;

再遍历链表2,统计链表2的长度len2以及拿到链表2的最后一个节点end2;

拿到四个变量后,判断end1是否和end2是同一个节点(内存地址相等),如果不等,不可能相交;如果相等,说明相交,但end不代表是第一个入环的节点。

假如len1是100,len2是80,head1先走20步,然后head1和head2一起走,最终一定会共同走到第一个相交的节点处。

怎么判断两个有环单链表的第一个相交节点?

三种拓扑结构:

①两个链表各自成环,不相交。

 ②先相交,再共同拥有一个环。

  

③先不相交,但共同拥有一个环。

  

怎么区分三种拓扑结构:

 如果loop1和loop2的内存地址一样,是②结构,等同于求两个无环链表相交。

 如果loop1≠loop2可能是①或③的情况,让loop1继续不断通过next往下走,

  如果loop1一路next之后转回自己了 ,还没遇到loop2,就是①的情况,两个链表不相交,返回null;

  如果loop1一路next之后遇到loop2了,就是③的情况,两个链表相交,返回loop1或loop2中的哪一个作为第一个相交的节点都对,因为loop1是距离链表1最近的相交节点,loop2是距离链表2最近的相交节点,都叫第一个相交的节点。

代码实现

  1 package class_03;
  2 
  3 public class Code_14_FindFirstIntersectNode {
  4 
  5     public static class Node {
  6         public int value;
  7         public Node next;
  8 
  9         public Node(int data) {
 10             this.value = data;
 11         }
 12     }
 13 
 14     public static Node getIntersectNode(Node head1, Node head2) {
 15         if (head1 == null || head2 == null) {
 16             return null;
 17         }
 18         Node loop1 = getLoopNode(head1);
 19         Node loop2 = getLoopNode(head2);
 20         if (loop1 == null && loop2 == null) {
 21             return noLoop(head1, head2);
 22         }
 23         if (loop1 != null && loop2 != null) {
 24             return bothLoop(head1, loop1, head2, loop2);
 25         }
 26         return null;
 27     }
 28 
 29     public static Node getLoopNode(Node head) {
 30         if (head == null || head.next == null || head.next.next == null) {
 31             return null;
 32         }
 33         Node n1 = head.next; // n1 -> slow
 34         Node n2 = head.next.next; // n2 -> fast
 35         while (n1 != n2) {
 36             if (n2.next == null || n2.next.next == null) {
 37                 return null;
 38             }
 39             n2 = n2.next.next;
 40             n1 = n1.next;
 41         }
 42         n2 = head; // n2 -> walk again from head
 43         while (n1 != n2) {
 44             n1 = n1.next;
 45             n2 = n2.next;
 46         }
 47         return n1;
 48     }
 49 
 50     public static Node noLoop(Node head1, Node head2) {
 51         if (head1 == null || head2 == null) {
 52             return null;
 53         }
 54         Node cur1 = head1;
 55         Node cur2 = head2;
 56         int n = 0;
 57         while (cur1.next != null) {
 58             n++;
 59             cur1 = cur1.next;
 60         }
 61         while (cur2.next != null) {
 62             n--;
 63             cur2 = cur2.next;
 64         }
 65         if (cur1 != cur2) {
 66             return null;
 67         }
 68         cur1 = n > 0 ? head1 : head2;
 69         cur2 = cur1 == head1 ? head2 : head1;
 70         n = Math.abs(n);
 71         while (n != 0) {
 72             n--;
 73             cur1 = cur1.next;
 74         }
 75         while (cur1 != cur2) {
 76             cur1 = cur1.next;
 77             cur2 = cur2.next;
 78         }
 79         return cur1;
 80     }
 81 
 82     public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
 83         Node cur1 = null;
 84         Node cur2 = null;
 85         if (loop1 == loop2) {
 86             cur1 = head1;
 87             cur2 = head2;
 88             int n = 0;
 89             while (cur1 != loop1) {
 90                 n++;
 91                 cur1 = cur1.next;
 92             }
 93             while (cur2 != loop2) {
 94                 n--;
 95                 cur2 = cur2.next;
 96             }
 97             cur1 = n > 0 ? head1 : head2;
 98             cur2 = cur1 == head1 ? head2 : head1;
 99             n = Math.abs(n);
100             while (n != 0) {
101                 n--;
102                 cur1 = cur1.next;
103             }
104             while (cur1 != cur2) {
105                 cur1 = cur1.next;
106                 cur2 = cur2.next;
107             }
108             return cur1;
109         } else {
110             cur1 = loop1.next;
111             while (cur1 != loop1) {
112                 if (cur1 == loop2) {
113                     return loop1;
114                 }
115                 cur1 = cur1.next;
116             }
117             return null;
118         }
119     }
120 
121     public static void main(String[] args) {
122         // 1->2->3->4->5->6->7->null
123         Node head1 = new Node(1);
124         head1.next = new Node(2);
125         head1.next.next = new Node(3);
126         head1.next.next.next = new Node(4);
127         head1.next.next.next.next = new Node(5);
128         head1.next.next.next.next.next = new Node(6);
129         head1.next.next.next.next.next.next = new Node(7);
130 
131         // 0->9->8->6->7->null
132         Node head2 = new Node(0);
133         head2.next = new Node(9);
134         head2.next.next = new Node(8);
135         head2.next.next.next = head1.next.next.next.next.next; // 8->6
136         System.out.println(getIntersectNode(head1, head2).value);
137 
138         // 1->2->3->4->5->6->7->4...
139         head1 = new Node(1);
140         head1.next = new Node(2);
141         head1.next.next = new Node(3);
142         head1.next.next.next = new Node(4);
143         head1.next.next.next.next = new Node(5);
144         head1.next.next.next.next.next = new Node(6);
145         head1.next.next.next.next.next.next = new Node(7);
146         head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
147 
148         // 0->9->8->2...
149         head2 = new Node(0);
150         head2.next = new Node(9);
151         head2.next.next = new Node(8);
152         head2.next.next.next = head1.next; // 8->2
153         System.out.println(getIntersectNode(head1, head2).value);
154 
155         // 0->9->8->6->4->5->6..
156         head2 = new Node(0);
157         head2.next = new Node(9);
158         head2.next.next = new Node(8);
159         head2.next.next.next = head1.next.next.next.next.next; // 8->6
160         System.out.println(getIntersectNode(head1, head2).value);
161 
162     }
163 
164 }

题目七

二分的小扩展。

posted @ 2020-02-12 12:21  阿江是个程序猿  阅读(198)  评论(0编辑  收藏  举报