Leetcode題解——數據結構之鏈表


1. 找出兩個鏈表的交點

鏈表是空節點,或者有一個值和一個指向下一個鏈表的指針,因此很多鏈表問題可以用遞歸來處理。

1. 找出兩個鏈表的交點

160. Intersection of Two Linked Lists (Easy)

例如以下示例中 A 和 B 兩個鏈表相交於 c1:

A:          a1 → a2
                    ↘
                      c1 → c2 → c3
                    ↗
B:    b1 → b2 → b3

但是不會出現以下相交的情況,因為每個節點只有一個 next 指針,也就只能有一個后繼節點,而以下示例中節點 c 有兩個后繼節點。

A:          a1 → a2       d1 → d2
                    ↘  ↗
                      c
                    ↗  ↘
B:    b1 → b2 → b3        e1 → e2

要求時間復雜度為 O(N),空間復雜度為 O(1)。如果不存在交點則返回 null。

設 A 的長度為 a + c,B 的長度為 b + c,其中 c 為尾部公共部分長度,可知 a + c + b = b + c + a。

當訪問 A 鏈表的指針訪問到鏈表尾部時,令它從鏈表 B 的頭部開始訪問鏈表 B;同樣地,當訪問 B 鏈表的指針訪問到鏈表尾部時,令它從鏈表 A 的頭部開始訪問鏈表 A。這樣就能控制訪問 A 和 B 兩個鏈表的指針能同時訪問到交點。

如果不存在交點,那么 a + b = b + a,以下實現代碼中 l1 和 l2 會同時為 null,從而退出循環。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode l1 = headA, l2 = headB; while (l1 != l2) { l1 = (l1 == null) ? headB : l1.next; l2 = (l2 == null) ? headA : l2.next; } return l1; }

如果只是判斷是否存在交點,那么就是另一個問題,即 編程之美 3.6 的問題。有兩種解法:

  • 把第一個鏈表的結尾連接到第二個鏈表的開頭,看第二個鏈表是否存在環;
  • 或者直接比較兩個鏈表的最后一個節點是否相同。

2. 鏈表反轉

206. Reverse Linked List (Easy)

遞歸

public ListNode reverseList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode next = head.next; ListNode newHead = reverseList(next); next.next = head; head.next = null; return newHead; }

頭插法

public ListNode reverseList(ListNode head) { ListNode newHead = new ListNode(-1); while (head != null) { ListNode next = head.next; head.next = newHead.next; newHead.next = head; head = next; } return newHead.next; }

3. 歸並兩個有序的鏈表

21. Merge Two Sorted Lists (Easy)

public ListNode mergeTwoLists(ListNode l1, ListNode l2) { if (l1 == null) return l2; if (l2 == null) return l1; if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } }

4. 從有序鏈表中刪除重復節點

83. Remove Duplicates from Sorted List (Easy)

Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
public ListNode deleteDuplicates(ListNode head) { if (head == null || head.next == null) return head; head.next = deleteDuplicates(head.next); return head.val == head.next.val ? head.next : head; }

5. 刪除鏈表的倒數第 n 個節點

19. Remove Nth Node From End of List (Medium)

Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode fast = head; while (n-- > 0) { fast = fast.next; } if (fast == null) return head.next; ListNode slow = head; while (fast.next != null) { fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return head; }

6. 交換鏈表中的相鄰結點

24. Swap Nodes in Pairs (Medium)

Given 1->2->3->4, you should return the list as 2->1->4->3.

題目要求:不能修改結點的 val 值,O(1) 空間復雜度。

public ListNode swapPairs(ListNode head) { ListNode node = new ListNode(-1); node.next = head; ListNode pre = node; while (pre.next != null && pre.next.next != null) { ListNode l1 = pre.next, l2 = pre.next.next; ListNode next = l2.next; l1.next = next; l2.next = l1; pre.next = l2; pre = l1; } return node.next; }

7. 鏈表求和

445. Add Two Numbers II (Medium)

Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7

題目要求:不能修改原始鏈表。

public ListNode addTwoNumbers(ListNode l1, ListNode l2) { Stack<Integer> l1Stack = buildStack(l1); Stack<Integer> l2Stack = buildStack(l2); ListNode head = new ListNode(-1); int carry = 0; while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) { int x = l1Stack.isEmpty() ? 0 : l1Stack.pop(); int y = l2Stack.isEmpty() ? 0 : l2Stack.pop(); int sum = x + y + carry; ListNode node = new ListNode(sum % 10); node.next = head.next; head.next = node; carry = sum / 10; } return head.next; } private Stack<Integer> buildStack(ListNode l) { Stack<Integer> stack = new Stack<>(); while (l != null) { stack.push(l.val); l = l.next; } return stack; }

8. 回文鏈表

234. Palindrome Linked List (Easy)

題目要求:以 O(1) 的空間復雜度來求解。

切成兩半,把后半段反轉,然后比較兩半是否相等。

public boolean isPalindrome(ListNode head) { if (head == null || head.next == null) return true; ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } if (fast != null) slow = slow.next; // 偶數節點,讓 slow 指向下一個節點 cut(head, slow); // 切成兩個鏈表 return isEqual(head, reverse(slow)); } private void cut(ListNode head, ListNode cutNode) { while (head.next != cutNode) { head = head.next; } head.next = null; } private ListNode reverse(ListNode head) { ListNode newHead = null; while (head != null) { ListNode nextNode = head.next; head.next = newHead; newHead = head; head = nextNode; } return newHead; } private boolean isEqual(ListNode l1, ListNode l2) { while (l1 != null && l2 != null) { if (l1.val != l2.val) return false; l1 = l1.next; l2 = l2.next; } return true; }

9. 分隔鏈表

725. Split Linked List in Parts(Medium)

Input:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
Explanation:
The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.

題目描述:把鏈表分隔成 k 部分,每部分的長度都應該盡可能相同,排在前面的長度應該大於等於后面的。

public ListNode[] splitListToParts(ListNode root, int k) { int N = 0; ListNode cur = root; while (cur != null) { N++; cur = cur.next; } int mod = N % k; int size = N / k; ListNode[] ret = new ListNode[k]; cur = root; for (int i = 0; cur != null && i < k; i++) { ret[i] = cur; int curSize = size + (mod-- > 0 ? 1 : 0); for (int j = 0; j < curSize - 1; j++) { cur = cur.next; } ListNode next = cur.next; cur.next = null; cur = next; } return ret; }

10. 鏈表元素按奇偶聚集

328. Odd Even Linked List (Medium)

Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
public ListNode oddEvenList(ListNode head) { if (head == null) { return head; } ListNode odd = head, even = head.next, evenHead = even; while (even != null && even.next != null) { odd.next = odd.next.next; odd = odd.next; even.next = even.next.next; even = even.next; } odd.next = evenHead; return head; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM