算法题解之链表
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 }
思路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 }
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 }
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 }
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 }
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 }
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 }
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
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 }
思路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>() { 以上是关于算法题解之链表的主要内容,如果未能解决你的问题,请参考以下文章