演算法:尋找無環或者有環的2個單向連結串列的相交節點
阿新 • • 發佈:2022-04-19
// 獲取相交節點 public static Node getNode(Node head1, Node head2) { if (head1 == null || head2 == null) { return null; } // 獲取第一個連結串列的入環節點 Node loop1 = getLoopNode(head1); // 獲取第二個連結串列的入環節點 Node loop2 = getLoopNode(head2); // 如果2個為空,則代表2個連結串列均無環 if (loop1 == null && loop2 == null) { return noLoop(head1, head2); } // 如果均有環 if (loop1 != null && loop2 != null) { return bothLoop(head1, loop1, head2, loop2); } return null; } // 獲取無環的2個連結串列的相交節點 public static Node noLoop(Node head1, Node head2) { int len1 = 0; int len2 = 0; Node n1 = head1; Node n2 = head2; // 獲取第一個連結串列的長度 while (n1.next != null) { len1++; n1 = n1.next; } // 獲取第二個連結串列的長度 while (n2.next != null) { len2++; n2 = n2.next; } // 如果尾部節點不一致,則2個連結串列無公共部分 if (n1 != n2) { return null; } // 求2個長度的差值 int c = Math.abs(len1 - len2); // 找到最長的連結串列 Node h = len1 > len2 ? head1 : head2; // 最短的連結串列 Node h2 = len1 > len2 ? head2 : head1; // 讓最長的連結串列多走c步,使2個連結串列的長度一致 while (c > 0) { h = h.next; c--; } // 2個連結串列同時遍歷,直到相等節點,則為相交節點 while (h != h2) { h = h.next; h2 = h2.next; } return h; } public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) { if (loop1 == loop2) { int len1 = 0; int len2 = 0; Node n1 = head1; Node n2 = head2; while (n1 != loop1) { len1++; n1 = n1.next; } while (n2 != loop1) { len2++; n2 = n2.next; } // 如果尾部節點不一致,則2個連結串列無公共部分 if (n1 != n2) { return null; } int c = Math.abs(len1 - len2); Node h = len1 > len2 ? head1 : head2; Node h2 = len1 > len2 ? head2 : head1; while (c > 0) { h = h.next; c--; } while (h != h2) { h = h.next; h2 = h2.next; } return h; } else { Node cur = loop1.next; while (cur != loop1) { if (cur == loop2) { return loop1; } cur = cur.next; } return null; } } public static Node getLoopNode(Node head) { if (head == null || head.next == null) { return null; } // 快慢指標,快指標一定會遇到慢指標 Node n1 = head.next; Node n2 = head.next.next; while (n2 != null && n2.next != null) { if (n1 == n2) { break; } n1 = n1.next; n2 = n2.next.next; } // 將快指標重置到頭節點,慢指標保留原地,2個指標同時走,一定會在入環節點相遇 n2 = head; while (n1 != null && n2 != null) { if (n1 == n2) { break; } n1 = n1.next; n2 = n2.next; } return n1; }