算法题解之链表

Posted coldyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法题解之链表相关的知识,希望对你有一定的参考价值。

Copy List with Random Pointers

复制带随机指针的链表

思路1:使用哈希表,需要消耗O(N)的额外空间。

 1 public class Solution {
 2     /**
 3      * @param head: The head of linked list with a random pointer.
 4      * @return: A new head of a deep copy of the list.
 5      */
 6     public RandomListNode copyRandomList(RandomListNode head) {
 7         // write your code here
 8         
 9         Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
10         RandomListNode cur = head;
11         RandomListNode copyDummy = new RandomListNode(0);
12         RandomListNode copyCur = copyDummy;
13         
14         while (cur != null) {
15             copyCur.next = new RandomListNode(cur.label);
16             copyCur = copyCur.next;
17             map.put(cur, copyCur);
18             cur = cur.next;
19         }
20         
21         cur = head;
22         while (cur != null) {
23             copyCur = map.get(cur);
24             copyCur.random = map.get(cur.random);
25             cur = cur.next;
26         }       
27         return copyDummy.next;
28     }
29 }
View Code

思路2:第一遍扫的时候巧妙运用next指针, 开始数组是1->2->3->4 。 然后扫描过程中 先建立copy节点 1->1`->2->2`->3->3`->4->4`, 然后第二遍copy的时候去建立边的copy, 拆分节点, 一边扫描一边拆成两个链表,这里用到两个dummy node。第一个链表变回 1->2->3 , 然后第二变成 1`->2`->3` 。消耗额外空间O(1)。

 1 public class Solution {
 2     /**
 3      * @param head: The head of linked list with a random pointer.
 4      * @return: A new head of a deep copy of the list.
 5      */
 6     public RandomListNode copyRandomList(RandomListNode head) {
 7         // write your code here
 8         copyNext(head);
 9         copyRandom(head);
10         return split(head);
11         
12     }
13     
14     public RandomListNode split(RandomListNode head) {
15         RandomListNode dummy = new RandomListNode(0);
16         RandomListNode cur = dummy;
17         
18         while (head != null) {
19             cur.next = head.next;
20             cur = cur.next;
21             head.next = head.next.next;
22             head = head.next;
23         }
24         return dummy.next;
25         
26     }
27     
28     public void copyRandom(RandomListNode head) {
29         
30         while (head != null) {
31             RandomListNode copy = head.next;
32             if (copy.random != null) {
33                 copy.random = copy.random.next;
34             }
35             head = head.next.next;
36         }
37         
38     }
39     
40     public void copyNext(RandomListNode head) {
41       
42         while (head != null) {
43             RandomListNode copy = new RandomListNode(head.label);
44             copy.next = head.next;
45             copy.random = head.random;
46             head.next = copy;
47             head = head.next.next;
48         }
49 
50     }
51 }
View Code

 

 

Convert Binary Search Tree to Doubly Linked List

将二叉查找树转换成双链表

思路:用分治法做,分治函数要返回该子树对应的双链表的头节点和尾节点。

 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 public class Solution {
22     /**
23      * @param root: The root of tree
24      * @return: the head of doubly list node
25      */
26     public DoublyListNode bstToDoublyList(TreeNode root) {  
27         // Write your code here
28         return helper(root).head;
29     }
30     
31     public Pair helper(TreeNode root) {
32         if (root == null) {
33             return new Pair(null, null);
34         }
35         Pair leftPair = helper(root.left);
36         Pair rightPair = helper(root.right);
37         DoublyListNode rootNode = new DoublyListNode(root.val);
38         rootNode.next = rightPair.head;
39         rootNode.prev = leftPair.tail;
40         
41         if (leftPair.head == null && rightPair.head == null) {
42             return new Pair(rootNode, rootNode);
43         } else if (leftPair.head == null) {
44             rightPair.head.prev = rootNode;
45             return new Pair(rootNode, rightPair.tail);
46         } else if (rightPair.head == null) {
47             leftPair.tail.next = rootNode;
48             return new Pair(leftPair.head, rootNode);
49         } else {
50             rightPair.head.prev = rootNode;
51             leftPair.tail.next = rootNode;
52             return new Pair(leftPair.head, rightPair.tail);
53         }
54         
55     }
56 }
57 
58 class Pair {
59     DoublyListNode head;
60     DoublyListNode tail;
61     Pair(DoublyListNode head, DoublyListNode tail) {
62         this.head = head;
63         this.tail = tail;
64     }
65 }
View Code

 

 

Convert Sorted List to Balanced BST

排序列表转换为二分查找树

思路:分治法。找到链表中点,中点作为根节点,左半段构造一个BST作为左子树,右半段构造一个BST作为右子树。

 1 /**
 2  * Definition for ListNode.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int val) {
 7  *         this.val = val;
 8  *         this.next = null;
 9  *     }
10  * }
11  * Definition of TreeNode:
12  * public class TreeNode {
13  *     public int val;
14  *     public TreeNode left, right;
15  *     public TreeNode(int val) {
16  *         this.val = val;
17  *         this.left = this.right = null;
18  *     }
19  * }
20  */ 
21 public class Solution {
22     /**
23      * @param head: The first node of linked list.
24      * @return: a tree node
25      */
26     public TreeNode sortedListToBST(ListNode head) {  
27         // write your code here
28         if (head == null) {
29             return null; 
30         }
31         
32         if (head.next == null) {
33             return new TreeNode(head.val);
34         }
35         
36         if (head.next.next == null) {
37             TreeNode root = new TreeNode(head.val);
38             root.right = new TreeNode(head.next.val);
39             return root;
40         }
41         
42         ListNode befMid = beforeMid(head);
43         TreeNode root = new TreeNode(befMid.next.val);
44         root.right = sortedListToBST(befMid.next.next);
45         befMid.next = null;
46         root.left = sortedListToBST(head);
47         
48         return root;
49         
50     }
51     
52     public ListNode beforeMid(ListNode head) {
53         ListNode cur = head;
54         int length = 0;
55         while (cur != null) {
56             cur = cur.next;
57             length++;
58         }
59         
60         int mid = (length + 1) / 2;
61         for(int i = 2; i <= mid -1; i++){
62             head = head.next;
63         }
64         
65         return head;
66     }
67 }
View Code

 

 

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         int sizeA = 0;
 7         ListNode curA = headA;
 8         while (curA != null) {
 9             curA = curA.next;
10             sizeA++;
11         }
12         
13         int sizeB = 0;
14         ListNode curB = headB;
15         while (curB != null) {
16             curB = curB.next;
17             sizeB++;
18         }
19         
20         int diff = Math.abs(sizeA - sizeB);
21         if (sizeA > sizeB) {
22             while (diff-- != 0) {
23                 headA = headA.next;
24             }
25         } else {
26             while (diff-- != 0) {
27                 headB = headB.next;
28             }
29         }
30         
31         while (headA != null) {
32             if (headA == headB) {
33                 return headA;
34             } else {
35                 headA = headA.next;
36                 headB = headB.next;
37             }
38         }
39         return null;
40     }
41 }
View Code

 

 

Linked List Cycle

带环链表

思路:先起一个快指针和一个慢指针,如果快慢指针能相遇,说明带环。

 1 /**
 2  * Definition for ListNode.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int val) {
 7  *         this.val = val;
 8  *         this.next = null;
 9  *     }
10  * }
11  */ 
12 public class Solution {
13     /**
14      * @param head: The first node of linked list.
15      * @return: True if it has a cycle, or false
16      */
17     public boolean hasCycle(ListNode head) {  
18         // write your code here
19         if (head == null || head.next == null) {
20             return false;
21         }
22         ListNode slow = head;
23         ListNode fast = head.next;
24         while (fast != null && fast.next != null) {
25             if (slow == fast) {
26                 return true;
27             }
28             slow = slow.next;
29             fast = fast.next.next;
30         }
31         return false;
32     }
33 }
View Code

 

 

Linked List Cycle II

带环链表II

思路:先起一个快指针和一个慢指针,快指针和慢指针重合时,从表头再起一个慢指针,两个慢指针继续走,相遇的地方就是环的入口。

 1 /**
 2  * Definition for ListNode.
 3  * public class ListNode {
 4  *     int val;
 5  *     ListNode next;
 6  *     ListNode(int val) {
 7  *         this.val = val;
 8  *         this.next = null;
 9  *     }
10  * }
11  */ 
12 public class Solution {
13     /**
14      * @param head: The first node of linked list.
15      * @return: The node where the cycle begins. 
16      *           if there is no cycle, return null
17      */
18     public ListNode detectCycle(ListNode head) {  
19         // write your code here
20         if (head == null || head.next == null) {
21             return null;
22         }
23         ListNode slow = head;
24         ListNode fast = head.next;
25         
26         while (slow != fast) {
27             if (fast == null || fast.next == null) {
28                 return null;
29             }
30             slow = slow.next;
31             fast = fast.next.next;
32         }
33         
34         while (head != slow.next) {
35             head = head.next;
36             slow = slow.next;
37         }
38         return head;
39         
40     }
41 }
View Code

 

 

merge k sorted lists

合并k个排序链表

思路1:分治法。

  时间复杂度分析:

 1 T(N,k) = T(N1, k/2) + T(N2, k/2) + N1 + N2
 2 
 3      = T(N1, k/2) + T(N2, k/2) + N
 4 
 5      = T(N11, k/4)  + T(N12, k/4) + N11 + N12 + T(N21, k/4) + T(N22, k/4)   + N21 + N22 + N
 6 
 7      = T(N11, k/4)  + T(N12, k/4) + N1 + T(N21, k/4) + T(N22, k/4) + N2 + N
 8 
 9      = T(N11, k/4)  + T(N12, k/4) + T(N21, k/4) + T(N22, k/4) + 2N
10 
11      ......
12 
13      = T(n1, 1) + T(n2, 1) +...+ T(nk, 1) + Nlgk = O(Nlgk)
14             
View Code
 1 public class Solution {
 2     /**
 3      * @param lists: a list of ListNode
 4      * @return: The head of one sorted list.
 5      */
 6     public ListNode mergeKLists(List<ListNode> lists) {
 7         if (lists.size() == 0) {
 8             return null;
 9         }
10         return mergeHelper(lists, 0, lists.size() - 1);
11     }
12     
13     private ListNode mergeHelper(List<ListNode> lists, int start, int end) {
14         if (start == end) {
15             return lists.get(start);
16         }
17         
18         int mid = start + (end - start) / 2;
19         ListNode left = mergeHelper(lists, start, mid);
20         ListNode right = mergeHelper(lists, mid + 1, end);
21         return mergeTwoLists(left, right);
22     }
23     
24     private ListNode mergeTwoLists(ListNode list1, ListNode list2) {
25         ListNode dummy = new ListNode(0);
26         ListNode tail = dummy;
27         while (list1 != null && list2 != null) {
28             if (list1.val < list2.val) {
29                 tail.next = list1;
30                 tail = list1;
31                 list1 = list1.next;
32             } else {
33                 tail.next = list2;
34                 tail = list2;
35                 list2 = list2.next;
36             }
37         }
38         if (list1 != null) {
39             tail.next = list1;
40         } else {
41             tail.next = list2;
42         }
43         
44         return dummy.next;
45     }
46 }
View Code

 思路2:最小堆

时间复杂度分析:T(N, k) = N * lgk = O(Nlgk)

 1 public class Solution {
 2     /**
 3      * @param lists: a list of ListNode
 4      * @return: The head of one sorted list.
 5      */
 6     public ListNode mergeKLists(List<ListNode> lists) {  
 7         // write your code here
 8         if (lists == null || lists.size()==0) {
 9             return null;
10         }
11         Comparator<ListNode> listNodeComparator = new Comparator<ListNode>() {
以上是关于算法题解之链表的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode题解——数据结构之链表

算法导论之链表

面试算法之链表(C++)

集合框架之链表集合算法

数据结构与算法之链表

集合框架之链表集合算法