目錄 題目描述 思路 程式(C++版&java版) 詳解 題目描述: 思路: 這道題實在是太經典,一道題裡面考察了幾個知識點: 1.鏈表是否有環的判斷 2.鏈表若有環,要找到環的入口節點 3.兩個鏈表的多種情況分析 另外,左老師講得實在是太贊了. 程式(詳解在後面): 詳解 先把幾種情況羅列一下: ...
目錄
題目描述
思路
程式(C++版&java版)
詳解
題目描述:
思路:
這道題實在是太經典,一道題裡面考察了幾個知識點:
1.鏈表是否有環的判斷
2.鏈表若有環,要找到環的入口節點
3.兩個鏈表的多種情況分析
另外,左老師講得實在是太贊了.
程式(詳解在後面):
1 //C++版,重寫了左老師的Java版 2 #include <iostream> 3 using namespace std; 4 5 //definition for singly-linked list. 6 struct ListNode 7 { 8 int val; 9 ListNode* next; 10 ListNode(int x) : val(x), next(NULL) {} 11 }; 12 13 ListNode* getLoopNode(ListNode* head) { 14 if (NULL == head || NULL == head->next || NULL == head->next->next) 15 return NULL; 16 ListNode* pSlow = head->next; 17 ListNode* pFast = head->next->next; 18 while (pSlow != pFast) { 19 if (NULL == pFast->next || NULL == pFast->next->next) { 20 return NULL; 21 } 22 pSlow = pSlow->next; 23 pFast = pFast->next->next; 24 } 25 pFast = head; //walk again to head,and speed equal.Or pSlow 26 while (pSlow != pFast) { 27 pSlow = pSlow->next; 28 pFast = pFast->next; 29 } 30 return pSlow;//Or pFast 31 } 32 33 ListNode* noLoop(ListNode* head1, ListNode* head2) { 34 if (NULL == head1 || NULL == head2) { 35 return NULL; 36 } 37 ListNode* cur1 = head1; 38 ListNode* cur2 = head2; 39 int n = 0; 40 while (NULL != cur1->next) { 41 ++n; 42 cur1 = cur1->next; 43 } 44 while (NULL != cur2->next) { 45 --n; 46 cur2 = cur2->next; 47 } 48 if (cur1 != cur2) { //tail node 49 return NULL; 50 } 51 cur1 = n > 0 ? head1 : head2; 52 cur2 = cur1 == head1 ? head2 : head1; 53 n = abs(n); 54 while (n--) { 55 cur1 = cur1->next; 56 } 57 while (cur1 != cur2) { 58 cur1 = cur1->next; 59 cur2 = cur2->next; 60 } 61 return cur1;//Or cur2 62 } 63 64 ListNode* bothLoop(ListNode* head1, ListNode*loop1, ListNode* head2, ListNode*loop2) { 65 ListNode* cur1 = NULL; 66 ListNode* cur2 = NULL; 67 if (loop1 == loop2) { 68 cur1 = head1; 69 cur2 = head2; 70 int n = 0; 71 while (cur1 != loop1) { 72 ++n; 73 cur1 = cur1->next; 74 } 75 while (cur2 != loop2) { 76 --n; 77 cur2 = cur2->next; 78 } 79 cur1 = n > 0 ? head1 : head2; 80 cur2 = cur1 == head1 ? head2 : head1; 81 n = abs(n); 82 while (n--) { 83 cur1 = cur1->next; 84 } 85 while (cur1 != cur2) { 86 cur1 = cur1->next; 87 cur2 = cur2->next; 88 } 89 return cur1;//Or cur2 90 } 91 else { 92 cur1 = loop1->next; 93 while (cur1 != loop1) { 94 if (cur1 == loop2) { 95 return loop1; 96 } 97 cur1 = cur1->next; 98 } 99 return NULL; 100 } 101 } 102 103 ListNode* getIntersectNode(ListNode* head1, ListNode* head2) { 104 if (NULL == head1 || NULL == head2) 105 return NULL; 106 ListNode* loop1 = getLoopNode(head1); 107 ListNode* loop2 = getLoopNode(head2); 108 if (NULL == loop1 && NULL == loop2) 109 return noLoop(head1, head2); 110 if (NULL != loop1 && NULL != loop2) 111 return bothLoop(head1, loop1, head2, loop2); 112 return NULL;//one of them have loop,so have no intersectionNode 113 } 114 115 int main() { 116 // 1->2->3->4->5->6->7->null 117 ListNode* head1 = new ListNode(1); 118 head1->next = new ListNode(2); 119 head1->next->next = new ListNode(3); 120 head1->next->next->next = new ListNode(4); 121 head1->next->next->next->next = new ListNode(5); 122 head1->next->next->next->next->next = new ListNode(6); 123 head1->next->next->next->next->next->next = new ListNode(7); 124 125 // 0->9->8->6->7->null 126 ListNode* head2 = new ListNode(0); 127 head2->next = new ListNode(9); 128 head2->next->next = new ListNode(8); 129 head2->next->next->next = head1->next->next->next->next->next; // 8->6 130 cout << getIntersectNode(head1, head2)->val << endl; 131 132 133 // 1->2->3->4->5->6->7->4... 134 head1 = new ListNode(1); 135 head1->next = new ListNode(2); 136 head1->next->next = new ListNode(3); 137 head1->next->next->next = new ListNode(4); 138 head1->next->next->next->next = new ListNode(5); 139 head1->next->next->next->next->next = new ListNode(6); 140 head1->next->next->next->next->next->next = new ListNode(7); 141 head1->next->next->next->next->next->next->next = head1->next->next->next;// 7->4 142 143 // 0->9->8->2... 144 head2 = new ListNode(0); 145 head2->next = new ListNode(9); 146 head2->next->next = new ListNode(8); 147 head2->next->next->next = head1->next; // 8->2 148 cout << getIntersectNode(head1, head2)->val << endl; 149 150 // 0->9->8->6->4->5->6... 151 head2 = new ListNode(0); 152 head2->next = new ListNode(9); 153 head2->next->next = new ListNode(8); 154 head2->next->next->next = head1->next->next->next->next->next; // 8->6 155 cout << getIntersectNode(head1, head2)->val << endl; 156 157 return 0; 158 }
1 //Java版.左老師給出的代碼,很贊 2 //package problems_2017_08_16; 3 4 public class Problem_03_FindFirstIntersectNode { 5 6 public static class Node { 7 public int value; 8 public Node next; 9 10 public Node(int data) { 11 this.value = data; 12 } 13 } 14 15 public static Node getIntersectNode(Node head1, Node head2) { 16 if (head1 == null || head2 == null) { 17 return null; 18 } 19 Node loop1 = getLoopNode(head1); 20 Node loop2 = getLoopNode(head2); 21 if (loop1 == null && loop2 == null) { 22 return noLoop(head1, head2); 23 } 24 if (loop1 != null && loop2 != null) { 25 return bothLoop(head1, loop1, head2, loop2); 26 } 27 return null; 28 } 29 30 public static Node getLoopNode(Node head) { 31 if (head == null || head.next == null || head.next.next == null) { 32 return null; 33 } 34 Node n1 = head.next; // n1 -> slow 35 Node n2 = head.next.next; // n2 -> fast 36 while (n1 != n2) { 37 if (n2.next == null || n2.next.next == null) { 38 return null; 39 } 40 n2 = n2.next.next; 41 n1 = n1.next; 42 } 43 n2 = head; // n2 -> walk again from head 44 while (n1 != n2) { 45 n1 = n1.next; 46 n2 = n2.next; 47 } 48 return n1; 49 } 50 51 public static Node noLoop(Node head1, Node head2) { 52 if (head1 == null || head2 == null) { 53 return null; 54 } 55 Node cur1 = head1; 56 Node cur2 = head2; 57 int n = 0; 58 while (cur1.next != null) { 59 n++; 60 cur1 = cur1.next; 61 } 62 while (cur2.next != null) { 63 n--; 64 cur2 = cur2.next; 65 } 66 if (cur1 != cur2) { 67 return null; 68 } 69 cur1 = n > 0 ? head1 : head2; 70 cur2 = cur1 == head1 ? head2 : head1; 71 n = Math.abs(n); 72 while (n != 0) { 73 n--; 74 cur1 = cur1.next; 75 } 76 while (cur1 != cur2) { 77 cur1 = cur1.next; 78 cur2 = cur2.next; 79 } 80 return cur1; 81 } 82 83 public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) { 84 Node cur1 = null; 85 Node cur2 = null; 86 if (loop1 == loop2) { 87 cur1 = head1; 88 cur2 = head2; 89 int n = 0; 90 while (cur1 != loop1) { 91 n++; 92 cur1 = cur1.next; 93 } 94 while (cur2 != loop2) { 95 n--; 96 cur2 = cur2.next; 97 } 98 cur1 = n > 0 ? head1 : head2; 99 cur2 = cur1 == head1 ? head2 : head1; 100 n = Math.abs(n); 101 while (n != 0) { 102 n--; 103 cur1 = cur1.next; 104 } 105 while (cur1 != cur2) { 106 cur1 = cur1.next; 107 cur2 = cur2.next; 108 } 109 return cur1; 110 } else { 111 cur1 = loop1.next; 112 while (cur1 != loop1) { 113 if (cur1 == loop2) { 114 return loop1; 115 } 116 cur1 = cur1.next; 117 } 118 return null; 119 } 120 } 121 122 public static void main(String[] args) { 123 // 1->2->3->4->5->6->7->null 124 Node head1 = new Node(1); 125 head1.next = new Node(2); 126 head1.next.next = new Node(3); 127 head1.next.next.next = new Node(4); 128 head1.next.next.next.next = new Node(5); 129 head1.next.next.next.next.next = new Node(6); 130 head1.next.next.next.next.next.next = new Node(7); 131 132 // 0->9->8->6->7->null 133 Node head2 = new Node(0); 134 head2.next = new Node(9); 135 head2.next.next = new Node(8); 136 head2.next.next.next = head1.next.next.next.next.next; // 8->6 137 System.out.println(getIntersectNode(head1, head2).value);//output:6 138 139 // 1->2->3->4->5->6->7->4... 140 head1 = new Node(1); 141 head1.next = new Node(2); 142 head1.next.next = new Node(3); 143 head1.next.next.next = new Node(4); 144 head1.next.next.next.next = new Node(5); 145 head1.next.next.next.next.next = new Node(6); 146 head1.next.next.next.next.next.next = new Node(7); 147 head1.next.next.next.next.next.next.next = head1.next.next.next; // 7->4 148 149 // 0->9->8->2... 150 head2 = new Node(0); 151 head2.next = new Node(9); 152 head2.next.next = new Node(8); 153 head2.next.next.next = head1.next; // 8->2 154 System.out.println(getIntersectNode(head1, head2).value);//output:2 155 156 // 0->9->8->6->4->5->6.. 157 head2 = new Node(0); 158 head2.next = new Node(9); 159 head2.next.next = new Node(8); 160 head2.next.next.next = head1.next.next.next.next.next; // 8->6 161 System.out.println(getIntersectNode(head1, head2).value);//output:4 162 System.out.println(getIntersectNode(head2, head1).value);//note the order //output:6 163 164 } 165 166 }
詳解
先把幾種情況羅列一下:
然後照著程式執行流程梳理思路:
0.判斷兩鏈表是否有環(分別找環入口結點,能找到則有環,否則無環):
若都無環,轉入第1步(可能是情況1或2);
若都有環,轉入第2步(可能是情況4或5或6);
若一個有環一個無環,直接返回NULL,因為如果他們相交,是不可能一個有環一個無環的(圖中情況3);
1.都無環的情況,退化到兩個無環鏈表找入口點的問題(可參見<劍指offer>和leetcode:Intersection of Two Linked Lists)
1.0 先判斷兩條鏈表的長度;
1.1 從頭節點開始走,更長的鏈表先走"長度之差"步,然後一起走,如果相遇,則為入口點(情況2);否則無交點(情況1)
2.都有環的情況,這種情況還要細分:
2.0 先判斷兩鏈表環入口點是否相同,若相同,則為情況4,轉入步驟2.1;若不同,則為情況5或6,轉入2.2;
2.1 如果為上圖中情況4,我們可以把兩鏈表交點作為"假想的尾部節點",然後就退化成兩個無環鏈表找交點的問題了;
2.2 為判斷兩鏈表是否有交點,我們可以從第一個環的入口節點的下一個節點開始next,如果遇到了第二個鏈表環的入口節點,則返回第一個鏈表的入口節點(情況5:題目說找出第一個相交的節點,其實我覺得返回第二個鏈表的入口節點也行);反之,若走了一圈沒遇到第二個鏈表環的入口節點,說明兩鏈表不相交(情況6);
至此,程式執行結束.設計很巧妙,要熟練掌握.