链表知识点总结

1. Linked List Cycle(判断链表是否有环)

思路:设置slow和fast两个指针,初始化为head和head.next。遇到slow == fast说明有环,遇到fast == null || fast.next == null说明无环。模版程序如下。

 1 public class Solution {
 2     public boolean hasCycle(ListNode head) {
 3         if (head == null) {
 4             return false;
 5         }
 6         ListNode slow = head;
 7         ListNode fast = head.next;
 8         while (fast != slow) {
 9             if (fast == null || fast.next == null) {
10                 return false;
11             }
12             fast = fast.next.next;
13             slow = slow.next;
14         }
15         return true;
16     }
17 }
View Code

2. Intersection of Two Linked Lists(两个链表相交的开始节点)

思路:把第一个链表的尾节点连到第二个链表的头节点,然后判断环的入口节点。

 1 public class Solution {
 2     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
 3         if (headA == null || headB == null) {
 4             return null;
 5         }
 6         ListNode node = headA;
 7         while (node.next != null) {
 8             node = node.next;
 9         }
10         node.next = headB;
11         ListNode intersection = listCycle(headA);
12         node.next = null;
13         return intersection;
14     }
15     public ListNode listCycle(ListNode head) {
16         ListNode slow = head;
17         ListNode fast = head.next;
18         while (fast != slow) {
19             if (fast == null || fast.next == null) {
20                 return null;
21             }
22             fast = fast.next.next;
23             slow = slow.next;
24         }
25         slow = head;
26         fast = fast.next;
27         while (slow != fast) {
28             slow = slow.next;
29             fast = fast.next;
30         }
31         return slow;
32     }
33 }
View Code

3. Sorted List

(1)快速排序

思路:先找到中间节点(模版程序,详细见代码里的getMiddlle()函数),然后建立三个dummy分别用来组成比中间节点值小于、等于和大于的节点,注意最后一定要把末尾节点的next域置为null!!!因为末尾节点不一定是原list里的最后一个节点,其next域可能空可能不空。然后递归的排序left和right链表,最后把left、mid和right这三条链表合并。

(2)归并排序链表

思路:先找到中点节点,然后分治思想先排序右边list,再让中间节点的next域为null,再排序左边的list,最后merge。注意该算法空间复杂度为O(1)而不是给数组归并排序时的O(n),因为merge过程植新建了一个dummy node而并没有像数组的归并排序那样开辟了O(n)的临时数组。

 1 public class Solution {
 2     public ListNode sortList(ListNode head) {
 3         if (head == null || head.next == null) {
 4             return head;
 5         }
 6         ListNode mid = getMiddle(head);
 7         ListNode right = sortList(mid.next);
 8         mid.next = null;
 9         ListNode left = sortList(head);
10         return merge(left, right);
11     }
12     public ListNode getMiddle(ListNode head) {
13         ListNode slow = head;
14         ListNode fast = head.next;
15         while (fast != null && fast.next != null) {
16             fast = fast.next.next;
17             slow = slow.next;
18         }
19         return slow;
20     }
21     public ListNode merge(ListNode head1, ListNode head2) {
22         ListNode dummy = new ListNode(0);
23         ListNode cur = dummy;
24         while (head1 != null && head2 != null) {
25             if (head1.val < head2.val) {
26                 cur.next = head1;
27                 head1 = head1.next;
28             } else {
29                 cur.next = head2;
30                 head2 = head2.next;
31             }
32             cur = cur.next;
33         }
34         if (head1 != null) {
35             cur.next = head1;
36         }
37         if (head2 != null) {
38             cur.next = head2;
39         }
40         return dummy.next;
41     }
42 }
View Code

 4. Convert Binary Search Tree to Doubly Linked List

Convert a binary search tree to doubly linked list with in-order traversal.

Example
Given a binary search tree:

    4
   / 
  2   5
 / 
1   3
return 1<->2<->3<->4<->5
题目

思路:分治思想,以root为根的BST,利用ResultType类记录其值最小的节点和值最大的节点,然后建立值为root.val的链表节点,它的prev与值最大节点相连(相互连接),它的next与值最小节点相连(相互连接)。

 1 /**
 2  * Definition of TreeNode:
 3  * public class TreeNode {
 4  *     public int val;
 5  *     public TreeNode left, right;
 6  *     public TreeNode(int val) {
 7  *         this.val = val;
 8  *         this.left = this.right = null;
 9  *     }
10  * }
11  * Definition for Doubly-ListNode.
12  * public class DoublyListNode {
13  *     int val;
14  *     DoublyListNode next, prev;
15  *     DoublyListNode(int val) {
16  *         this.val = val;
17  *         this.next = this.prev = null;
18  *     }
19  * }
20  */
21 class ResultType {
22     DoublyListNode first;
23     DoublyListNode last;
24     public ResultType(DoublyListNode first, DoublyListNode last) {
25         this.first = first;
26         this.last = last;
27     }
28 }
29 public class Solution {
30     /**
31      * @param root: The root of tree
32      * @return: the head of doubly list node
33      */
34     public DoublyListNode bstToDoublyList(TreeNode root) {
35         // Write your code here
36         return helper(root).first;
37     }
38     public ResultType helper(TreeNode root) {
39         if (root == null) {
40             return new ResultType(null, null);
41         }
42         ResultType left = helper(root.left);
43         ResultType right = helper(root.right);
44         DoublyListNode node = new DoublyListNode(root.val);
45         ResultType result = new ResultType(null, null);
46         if (root.left == null) {
47             result.first = node;
48         } else {
49             result.first = left.first;
50             node.prev = left.last;
51             left.last.next = node;
52         }
53         if (root.right == null) {
54             result.last = node;
55         } else {
56             result.last = right.last;
57             node.next = right.first;
58             right.first.prev = node;
59         }
60         return result;
61     }
62 }
View Code

5. Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

思路I:分治法,将问题归结到合并两个有序链表的问题上。

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode mergeKLists(ListNode[] lists) {
11         //Divide Conquer
12         if (lists == null || lists.length == 0) {
13             return null;
14         }
15         return mergeHelper(lists, 0, lists.length - 1);
16     }
17     public ListNode mergeHelper(ListNode[] lists, int start, int end) {
18         if (start == end) {
19             return lists[start];
20         }
21         int mid = start + (end - start) / 2;
22         ListNode left = mergeHelper(lists, start, mid);
23         ListNode right = mergeHelper(lists, mid + 1, end);
24         return mergeTwoLists(left, right);
25     }
26     public ListNode mergeTwoLists(ListNode left, ListNode right) {
27         ListNode dummy = new ListNode(0);
28         ListNode cur = dummy;
29         while (left != null && right != null) {
30             if (left.val < right.val) {
31                 cur.next = left;
32                 left = left.next;
33             } else {
34                 cur.next = right;
35                 right = right.next;
36             }
37             cur = cur.next;
38         }
39         if (left != null) {
40             cur.next = left;
41         }
42         if (right != null) {
43             cur.next = right;
44         }
45         return dummy.next;
46     }
47 }
View Code

思路II:小根堆

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode mergeKLists(ListNode[] lists) {
11         // Minimum Heap
12         if (lists == null || lists.length == 0) {
13             return null;
14         }
15         PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
16             public int compare(ListNode a, ListNode b) {
17                 return a.val - b.val;
18             }
19         });
20         for (int i = 0; i < lists.length; i++) {
21             //remove empty list
22             if (lists[i] != null) {
23                 pq.offer(lists[i]);
24             }
25         }
26         ListNode dummy = new ListNode(0);
27         ListNode cur = dummy;
28         while (!pq.isEmpty()) {
29             ListNode node = pq.poll();
30             cur.next = node;
31             cur = cur.next;
32             if (node.next != null) {
33                 pq.offer(node.next);
34             }
35         }
36         //此句多余,应为到最后一个元素,其next指针一定为空。
37         //因为都是有序链表,最后一个元素一定是某一条链表的末尾节点,其next域为空
38         //cur.next = null;
39         return dummy.next;
40     }
41 }
View Code

6. Insertion Sort List

Sort a linked list using insertion sort.

思路:pre指针指向每次要插入的元素的前一个位置,依次遍历节点插入即可。注意pre不必每次从头开始移动到插入位置,只需要当待插入元素比pre.next节点的值大才返回到头开始选择插入位置。

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode insertionSortList(ListNode head) {
11         if (head == null || head.next == null) {
12             return head;
13         }
14         ListNode dummy = new ListNode(0);
15         ListNode pre = dummy;
16         ListNode cur = head;
17         while (cur != null) {
18             ListNode next = cur.next;
19             // 避免pre指针每次都从头开始移动
20             if (pre.next == null || pre.next.val > cur.val) {
21                 pre = dummy;
22             }
23             while (pre.next != null && pre.next.val <= cur.val) {
24                 pre = pre.next;
25             }
26             cur.next = pre.next;
27             pre.next = cur;
28             cur = next;
29         }
30         return dummy.next;
31     }
32 }
View Code
原文地址:https://www.cnblogs.com/choumeng/p/6410247.html