Leetcode version 2
148. Sort List
题目:Sort a linked list in O(n log n) time using constant space complexity.
题意:排序链表
思路I:merge sort
复杂度分析:时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 10 // merge sort version 11 class Solution { 12 public ListNode sortList(ListNode head) { 13 if (head == null || head.next == null) { 14 return head; 15 } 16 ListNode middle = getMiddle(head); 17 ListNode rightHead = middle.next; 18 middle.next = null; 19 ListNode left = sortList(head); 20 ListNode right = sortList(rightHead); 21 return merge(left, right); 22 } 23 public ListNode getMiddle(ListNode head) { 24 if (head == null || head.next == null) { 25 return head; 26 } 27 ListNode slow = head; 28 ListNode fast = head.next; 29 while (fast != null && fast.next != null) { 30 slow = slow.next; 31 fast = fast.next.next; 32 } 33 return slow; 34 } 35 public ListNode merge(ListNode left, ListNode right) { 36 ListNode dummy = new ListNode(0); 37 ListNode cur = dummy; 38 while (left != null && right != null) { 39 if (left.val <= right.val) { 40 cur.next = left; 41 left = left.next; 42 } else { 43 cur.next = right; 44 right = right.next; 45 } 46 cur = cur.next; 47 } 48 if (left != null) { 49 cur.next = left; 50 } 51 if (right != null) { 52 cur.next = right; 53 } 54 return dummy.next; 55 } 56 }
思路II:quick sort
复杂度分析:时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 10 // quick sort version 11 class Solution { 12 public ListNode sortList(ListNode head) { 13 if (head == null || head.next == null) { 14 return head; 15 } 16 ListNode middle = getMiddle(head); 17 ListNode leftDummy = new ListNode(0), leftTail = leftDummy; 18 ListNode middleDummy = new ListNode(0), middleTail = middleDummy; 19 ListNode rightDummy = new ListNode(0), rightTail = rightDummy; 20 while (head != null) { 21 if ( head.val < middle.val) { 22 leftTail.next = head; 23 leftTail = leftTail.next; 24 } else if (head.val == middle.val) { 25 middleTail.next = head; 26 middleTail = middleTail.next; 27 } else { 28 rightTail.next = head; 29 rightTail = rightTail.next; 30 } 31 head = head.next; 32 } 33 leftTail.next = null; middleTail.next = null; rightTail.next = null; 34 ListNode left = sortList(leftDummy.next); 35 ListNode right = sortList(rightDummy.next); 36 return merge(merge(left, middleDummy.next), right); 37 } 38 public ListNode getMiddle(ListNode head) { 39 if (head == null || head.next == null) { 40 return head; 41 } 42 ListNode slow = head; 43 ListNode fast = head.next; 44 while (fast != null && fast.next != null) { 45 slow = slow.next; 46 fast = fast.next.next; 47 } 48 return slow; 49 } 50 public ListNode merge(ListNode left, ListNode right) { 51 ListNode dummy = new ListNode(0); 52 ListNode cur = dummy; 53 while (left != null && right != null) { 54 if (left.val <= right.val) { 55 cur.next = left; 56 left = left.next; 57 } else { 58 cur.next = right; 59 right = right.next; 60 } 61 cur = cur.next; 62 } 63 if (left != null) { 64 cur.next = left; 65 } 66 if (right != null) { 67 cur.next = right; 68 } 69 return dummy.next; 70 } 71 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 10 // insert sort 11 class Solution { 12 public ListNode insertionSortList(ListNode head) { 13 if (head == null || head.next == null) { 14 return head; 15 } 16 ListNode dummy = new ListNode(0); 17 ListNode pre = dummy; 18 ListNode cur = head; 19 while (cur != null) { 20 ListNode after = cur.next; 21 while (pre != null && pre.next != null && pre.next.val < cur.val) { 22 pre = pre.next; 23 } 24 cur.next = pre.next; 25 pre.next = cur; 26 pre = dummy; 27 cur = after; 28 } 29 return dummy.next; 30 } 31 }
143. Reorder List
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… You must do this in-place without altering the nodes' values. For example, Given {1,2,3,4}, reorder it to {1,4,2,3}.
题意:循环连接链表元素
思路:反转链表后半部分指针指向,然后对两半链表,当两个节点都非空并且不相等时,分别从前往后和从后往前执行指针修改操作,不满足条件是跳出循环,此时指针修改工作全部完成。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public void reorderList(ListNode head) { 11 if (head == null || head.next == null || head.next.next == null) { 12 return; 13 } 14 ListNode middle = getMiddle(head); 15 ListNode prev = null; 16 ListNode cur = middle; 17 while (cur != null) { 18 ListNode after = cur.next; 19 cur.next = prev; 20 prev = cur; 21 cur = after; 22 } 23 ListNode front = head; 24 ListNode tail = prev; 25 while (front != null && tail != null && front != tail) { 26 ListNode frontNext = front.next; 27 ListNode tailNext = tail.next; 28 tail.next = front.next; 29 front.next = tail; 30 front = frontNext; 31 tail = tailNext; 32 } 33 } 34 public ListNode getMiddle(ListNode head) { 35 if (head == null || head.next == null) { 36 return head; 37 } 38 ListNode slow = head; 39 ListNode fast = head.next; 40 while (fast != null && fast.next != null) { 41 slow = slow.next; 42 fast = fast.next.next; 43 } 44 return slow; 45 } 46 }
2. Add Two Numbers
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Example Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807.
题意:求两个数的和,链表方式存储数,低位在前,高位在后。
思路:一位一位的求即可,注意每次计算好进位。
易错点:当两个链表其中有一个链表走到头为null时,不要再往下移动指针了,否则会出现空指针异。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 11 if (l1 == null) { 12 return l2; 13 } 14 if (l2 == null) { 15 return l1; 16 } 17 ListNode cur1 = l1, cur2 = l2; 18 ListNode dummy = new ListNode(0), cur = dummy; 19 int carry = 0, sum = 0; 20 while (cur1 != null || cur2 != null) { 21 sum = carry; 22 if (cur1 != null) { 23 sum += cur1.val; 24 // 这里一定要注意,往下后移动是有条件的,只有当前指针非空才往后移动指针,否则会报空指针异常错误,所以下面这行代码一定要写在if内! 25 cur1 = cur1.next; 26 } 27 if (cur2 != null) { 28 sum += cur2.val; 29 // 这里一定要注意,往下后移动是有条件的,只有当前指针非空才往后移动指针,否则会报空指针异常错误,所以下面这行代码一定要写在if内! 30 cur2 = cur2.next; 31 } 32 int result = sum % 10; 33 carry = sum / 10; 34 cur.next = new ListNode(result); 35 cur = cur.next; 36 } 37 if (carry != 0) { 38 cur.next = new ListNode(carry); 39 } 40 return dummy.next; 41 } 42 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Follow up: What if you cannot modify the input lists? In other words, reversing the lists is not allowed. Example: Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 8 -> 0 -> 7
题意:与上面一道题相反,求两个数的和,链表方式存储,高位在前,低位在后。
思路:为了能跟上面一道题的做法一样,由于不能改动原链表,所以只需要用栈来实现高低位的逆序,从而就可以用上面一道题的方法求解。记住栈是可以反转的!
复杂度分析:时间复杂度O(n),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 11 if (l1 == null) { 12 return l2; 13 } 14 if (l2 == null) { 15 return l1; 16 } 17 Stack<Integer> stack1 = new Stack<Integer>(); 18 Stack<Integer> stack2 = new Stack<Integer>(); 19 ListNode cur1 = l1, cur2 = l2; 20 while (cur1 != null) { 21 stack1.push(cur1.val); 22 cur1 = cur1.next; 23 } 24 while (cur2 != null) { 25 stack2.push(cur2.val); 26 cur2 = cur2.next; 27 } 28 ListNode dummy = new ListNode(0), cur = dummy; 29 int carry = 0, sum = 0; 30 while (!stack1.isEmpty() || !stack2.isEmpty()) { 31 sum = carry; 32 if (!stack1.isEmpty()) { 33 sum += stack1.pop(); 34 } 35 if (!stack2.isEmpty()) { 36 sum += stack2.pop(); 37 } 38 int result = sum % 10; 39 carry = sum / 10; 40 ListNode node = new ListNode(result); 41 node.next = cur.next; 42 cur.next = node; 43 } 44 if (carry != 0) { 45 ListNode node = new ListNode(carry); 46 node.next = cur.next; 47 cur.next = node; 48 } 49 return dummy.next; 50 } 51 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
题意:拷贝一份带有随机指针的链表
思路I:先拷贝节点,再拷贝random,拷贝random时需要知道原链表节点的random指针指向的节点在新链表节点中是指向哪个节点,所以在拷贝节点的时候就要用一个Map拷贝新老节点的映射,以便拷贝random节点时能从老的random节点快速定位到新的random节点。
复杂度分析:时间复杂度O(n),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 public RandomListNode copyRandomList(RandomListNode head) { 11 if (head == null) { 12 return null; 13 } 14 Map<RandomListNode, RandomListNode> map = new HashMap<>(); 15 RandomListNode cur1 = head; 16 RandomListNode dummy = new RandomListNode(0), cur2 = dummy; 17 while (cur1 != null) { 18 RandomListNode newNode = new RandomListNode(cur1.label); 19 map.put(cur1, newNode); 20 cur2.next = newNode; 21 cur1 = cur1.next; 22 cur2 = cur2.next; 23 } 24 cur1 = head; 25 cur2 = dummy.next; 26 while (cur1 != null) { 27 if (cur1.random != null) { 28 RandomListNode oldNode = cur1.random; 29 RandomListNode newNode = map.get(oldNode); 30 cur2.random = newNode; 31 } 32 cur1 = cur1.next; 33 cur2 = cur2.next; 34 } 35 return dummy.next; 36 } 37 }
思路II:节点和random同时拷贝,map存储新老节点的映射关系。
复杂度分析:时间复杂度O(n),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 public RandomListNode copyRandomList(RandomListNode head) { 11 if (head == null) { 12 return null; 13 } 14 Map<RandomListNode, RandomListNode> map = new HashMap<>(); 15 RandomListNode cur1 = head; 16 RandomListNode dummy = new RandomListNode(0), cur2 = dummy; 17 while (cur1 != null) { 18 RandomListNode newNode = new RandomListNode(cur1.label); 19 map.put(cur1, newNode); 20 cur2.next = newNode; 21 cur2 = cur2.next; 22 if (cur1.random != null) { 23 if (!map.containsKey(cur1.random)) { 24 RandomListNode node = new RandomListNode(cur1.random.label); 25 map.put(cur1.random, node); 26 } 27 cur2.random = map.get(cur1.random); 28 } 29 cur1 = cur1.next; 30 } 31 return dummy.next; 32 } 33 }
思路III:第一遍扫的时候巧妙运用next指针, 开始数组是1->2->3。 然后扫描过程中 先建立copy节点 1->1`->2->2`->3->3`, 然后第二遍copy的时候去建立边的copy, 拆分节点, 一边扫描一边拆成两个链。第一个链表变回 1->2->3 , 然后第二变成 1`->2`->3。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 public RandomListNode copyRandomList(RandomListNode head) { 11 if (head == null) { 12 return null; 13 } 14 copyNext(head); 15 copyRandom(head); 16 return split(head); 17 } 18 public void copyNext(RandomListNode head) { 19 while (head != null) { 20 RandomListNode newNode = new RandomListNode(head.label); 21 newNode.next = head.next; 22 head.next = newNode; 23 head = head.next.next; 24 } 25 } 26 public void copyRandom(RandomListNode head) { 27 while (head != null) { 28 if (head.random != null) { 29 head.next.random = head.random.next; 30 } 31 head = head.next.next; 32 } 33 } 34 public RandomListNode split(RandomListNode head) { 35 RandomListNode newHead = head.next; 36 while (head != null) { 37 RandomListNode cur = head.next; 38 head.next = head.next.next; 39 if (cur.next != null) { 40 cur.next = cur.next.next; 41 } 42 head = head.next; 43 } 44 return newHead; 45 } 46 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1. Example: Given the sorted linked list: [-10,-3,0,5,9], One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST: 0 / \ -3 9 / / -10 5
题意:将升序链表转化成平衡二叉树
思路:中间节点对应的树节点的左子树为链表中间节点左边的节点集合:先找中间节点,同时要记录该中间节点的前一个节点后后一个节点,方便断开链表和递归,然后中间节点对应的树节点的右子树为链表中间节点右边的节点集合,递归下去即可。
复杂度分析:时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 /** 10 * Definition for a binary tree node. 11 * public class TreeNode { 12 * int val; 13 * TreeNode left; 14 * TreeNode right; 15 * TreeNode(int x) { val = x; } 16 * } 17 */ 18 class Solution { 19 public TreeNode sortedListToBST(ListNode head) { 20 if (head == null) { 21 return null; 22 } 23 if (head.next == null) { 24 TreeNode leaveNode = new TreeNode(head.val); 25 return leaveNode; 26 } 27 ListNode slow = head, fast = head.next; 28 ListNode pre = null, cur = null, after = null; 29 while (fast != null && fast.next != null) { 30 pre = slow; 31 slow = slow.next; 32 fast = fast.next.next; 33 } 34 cur = slow; 35 after = cur.next; 36 if (pre != null) { 37 pre.next = null; 38 } 39 cur.next = null; 40 TreeNode curNode = new TreeNode(cur.val); 41 // 这里一定要注意,只有当pre不为null时,才递归。当pre为null时,curNode.left为null,head不为空,如果此时递归就会错误。 42 if (pre != null) { 43 curNode.left = sortedListToBST(head); 44 } 45 curNode.right = sortedListToBST(after); 46 return curNode; 47 } 48 }
思路II:这种思路不用改变链表结构。还是先找到中间节点,递归另写一个函数,因为入参有两个:head和tail,分别代表当前链表的首节点和尾节点,尾节点初始为null。递归退出的条件是当head==tail,返回null。
复杂度分析:时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 /** 10 * Definition for a binary tree node. 11 * public class TreeNode { 12 * int val; 13 * TreeNode left; 14 * TreeNode right; 15 * TreeNode(int x) { val = x; } 16 * } 17 */ 18 class Solution { 19 public TreeNode sortedListToBST(ListNode head) { 20 if (head == null) { 21 return null; 22 } 23 return toBST(head, null); 24 } 25 public TreeNode toBST(ListNode head, ListNode tail) { 26 if (head == tail) { 27 return null; 28 } 29 ListNode slow = head, fast = head.next; 30 while (fast != tail && fast.next != tail) { 31 slow = slow.next; 32 fast = fast.next.next; 33 } 34 TreeNode node = new TreeNode(slow.val); 35 node.left = toBST(head, slow); 36 node.right = toBST(slow.next, tail); 37 return node; 38 } 39 }
86. Partition List
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions. For example, Given 1->4->3->2->5->2 and x = 3, return 1->2->2->4->3->5.
题意:将链表中所有小于x的节点都放在大于等于x的节点的前面,不改变节点之间的顺序,即相当于quick sort中的一次partition。
思路:建立连个dummy节点,其中一个dummy节点用来连接链表中值小于x的那些节点,另外一个dummy节点用来连接链表中值大于等于x的那些节点。最后将两条新链表连接起来即可。
复杂度分析:时间复杂度O(n),空间复杂度O(1)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode partition(ListNode head, int x) { 11 if (head == null || head.next == null) { 12 return head; 13 } 14 ListNode dummy1 = new ListNode(0), cur1 = dummy1; 15 ListNode dummy2 = new ListNode(0), cur2 = dummy2; 16 ListNode cur = head; 17 while (cur != null) { 18 if (cur.val < x) { 19 cur1.next = cur; 20 cur1 = cur1.next; 21 } else { 22 cur2.next = cur; 23 cur2 = cur2.next; 24 } 25 cur = cur.next; 26 } 27 cur1.next = null; 28 cur2.next = null; 29 cur1.next = dummy2.next; 30 return dummy1.next; 31 } 32 }
725. Split Linked List in Parts
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a (singly) linked list with head node root, write a function to split the linked list into k consecutive linked list "parts". The length of each part should be as equal as possible: no two parts should have a size differing by more than 1. This may lead to some parts being null. The parts should be in order of occurrence in the input list, and parts occurring earlier should always have a size greater than or equal parts occurring later. Return a List of ListNode's representing the linked list parts that are formed. Examples 1->2->3->4, k = 5 // 5 equal parts [ [1], [2], [3], [4], null ] Example 1: Input: root = [1, 2, 3], k = 5 Output: [[1],[2],[3],[],[]] Explanation: The input and each element of the output are ListNodes, not arrays. For example, the input root has root.val = 1, root.next.val = 2, \root.next.next.val = 3, and root.next.next.next = null. The first element output[0] has output[0].val = 1, output[0].next = null. The last element output[4] is null, but it's string representation as a ListNode is []. Example 2: 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. Note: The length of root will be in the range [0, 1000]. Each value of a node in the input will be an integer in the range [0, 999]. k will be an integer in the range [1, 50].
题意:将链表分成k个部分存储到一个数组里
思路:前后指针pre和cur,分别指向当前数组要存储的头节点和该头结点的上一个节点,初始化分别为null和head。然后循环k次,将数组的每个位置填上相应的链表头结点。每次pre和cur移动的次数取决于链表长度length / k和length % k。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode[] splitListToParts(ListNode root, int k) { 11 if (k <= 0) { 12 return new ListNode[0]; 13 } 14 ListNode[] result = new ListNode[k]; 15 int count = getCount(root); 16 int base = count / k; 17 int remain = count % k; 18 ListNode pre = null, cur = root; 19 for (int i = 0; i < k; i++) { 20 result[i] = cur; 21 for (int j = 0; j < base; j++) { 22 pre = cur; 23 cur = cur.next; 24 } 25 if (remain > 0) { 26 pre = cur; 27 cur = cur.next; 28 remain--; 29 } 30 if (pre != null) { 31 pre.next = null; 32 } 33 } 34 return result; 35 } 36 public int getCount(ListNode root) { 37 int count = 0; 38 while (root != null) { 39 count++; 40 root = root.next; 41 } 42 return count; 43 } 44 }
328. Odd Even Linked List
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes. You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity. Example: Given 1->2->3->4->5->NULL, return 1->3->5->2->4->NULL. Note: The relative order inside both the even and odd groups should remain as it was in the input. The first node is considered odd, the second node even and so on ...
题意:将链表的奇偶节点分开,不改变奇偶节点的内部顺序。
思路I:分别建立两个dummy节点分别串链表中的奇节点和偶节点,用一个计数器count来表示当前节点是奇数节点还是偶数节点,最后连接两串两串链表即可。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode oddEvenList(ListNode head) { 11 if (head == null || head.next == null) { 12 return head; 13 } 14 ListNode dummyOdd = new ListNode(0), curOdd = dummyOdd; 15 ListNode dummyEven = new ListNode(0), curEven = dummyEven; 16 ListNode cur = head; 17 int count = 0; 18 while (cur != null) { 19 count++; 20 if (count % 2 == 1) { 21 curOdd.next = cur; 22 curOdd = curOdd.next; 23 } else { 24 curEven.next = cur; 25 curEven = curEven.next; 26 } 27 cur = cur.next; 28 } 29 curOdd.next = null; 30 curEven.next = null; 31 curOdd.next = dummyEven.next; 32 return dummyOdd.next; 33 } 34 }
思路II:一次性将奇偶节点分别串好,用odd和even分别指向奇偶节点,初始分别为head和head.next,当even != null && even.next != null时,odd.next = odd.next.next; even.next = even.next.next; 然后odd和even都往后移动一位。退出循环后,将even的next域指向偶节点链表的头结点(需要事先存储)。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode oddEvenList(ListNode head) { 11 if (head == null || head.next == null) { 12 return head; 13 } 14 ListNode odd = head, even = head.next, evenHead = even; 15 while (even != null && even.next != null) { 16 odd.next = odd.next.next; 17 even.next = even.next.next; 18 odd = odd.next; 19 even =even.next; 20 } 21 odd.next = evenHead; 22 return head; 23 } 24 }
19. Remove Nth Node From End of List
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a linked list, remove the nth node from the end of list and return its head. For example, 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. Note: Given n will always be valid. Try to do this in one pass.
题意:删除链表的倒数第n个节点,要求一遍删除。
思路I:最后返回的头结点不能确定,所以先建立一个dummy节点,其next指向head。由于要求一遍删除,就不能先统计链表的长度然后删除正数第length + 1 - n个节点了。由于是倒数,不能直接正数来删除,所以很容易想到用栈来反转原链表,记得将dummy节点也压入栈中。然后从栈中弹出n个节点,此时栈顶节点就是倒数第n个节点的前一个节点,获取到这个节点后就很容易了。
复杂度分析:时间复杂度O(n),空间复杂度O(n)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode removeNthFromEnd(ListNode head, int n) { 11 if (head == null) { 12 return head; 13 } 14 ListNode dummy = new ListNode(0), cur = dummy; 15 dummy.next = head; 16 Stack<ListNode> stack = new Stack<>(); 17 while (cur != null) { 18 stack.push(cur); 19 cur = cur.next; 20 } 21 for (int i = 0; i < n; i++) { 22 stack.pop(); 23 } 24 ListNode pre = stack.peek(); 25 pre.next = pre.next.next; 26 return dummy.next; 27 } 28 }
思路II:前后指针pre和cur,初始pre=dummy,cur从dummy开始后移n步,也就是说pre和cur保持n步的距离。然后pre和cur每次都后移一位,直到cur移动到链表末尾,此时pre所指的节点就是倒数第n个节点的前一个节点,找到该节点之后就和容易了。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode removeNthFromEnd(ListNode head, int n) { 11 if (head == null) { 12 return head; 13 } 14 ListNode dummy = new ListNode(0); 15 dummy.next = head; 16 ListNode pre = dummy, cur = dummy; 17 for (int i = 0; i < n; i++) { 18 cur = cur.next; 19 } 20 while (cur.next != null) { 21 pre = pre.next; 22 cur = cur.next; 23 } 24 pre.next = pre.next.next; 25 return dummy.next; 26 } 27 }
24. Swap Nodes in Pairs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a linked list, swap every two adjacent nodes and return its head. For example, Given 1->2->3->4, you should return the list as 2->1->4->3. Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.
题意:每两个节点为一组反转,不够两个的保持原来的节点顺序。
思路:因为最后返回的头结点会改变,所以建立dummy节点,其next域指向head。cur从dummy节点开始,如果cur.next != null && cur.next.next != null说明cur节点的后面有两个节点,可以做交换操作(1. 第1个节点的next指向第3个节点 2. 2个节点反转,即第2个节点的next指向第1个节点 3. cur指向反转后的第2个节点,即反转前cur后面的第一个节点),然后执行交换操作,cur后移两步,再进行下一次循环。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode swapPairs(ListNode head) { 11 if (head == null || head.next == null) { 12 return head; 13 } 14 ListNode dummy = new ListNode(0), cur = dummy; 15 dummy.next = head; 16 while (cur.next != null && cur.next.next != null) { 17 ListNode first = cur.next; 18 ListNode second = cur.next.next; 19 first.next = second.next; 20 second.next = first; 21 cur.next = second; 22 cur = cur.next.next; 23 } 24 return dummy.next; 25 } 26 }
25. Reverse Nodes in k-Group
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. You may not alter the values in the nodes, only nodes itself may be changed. Only constant memory is allowed. For example, Given this linked list: 1->2->3->4->5 For k = 2, you should return: 2->1->4->3->5 For k = 3, you should return: 3->2->1->4->5
题意:是上一题的扩展版本,每k个节点为一组反转,不够k个的保持原来的节点顺序。
思路:因为最后返回的头结点会改变,所以建立dummy节点,其next域指向head。cur从dummy节点开始,循环先判断cur的后面有没有k个节点,如果有,进行k个节点的反转操作(1. k个节点反转 2. 第1个节点的next指向第k+1个节点 3. cur指向反转后的第k个节点,即反转前cur后面的第一个节点),然后cur移动到后面的k个节点的最后一个节点。继续进行下一轮循环的判断,当cur后面没有k个节点时,结束循环。
复杂度分析:时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 class Solution { 10 public ListNode reverseKGroup(ListNode head, int k) { 11 if (head == null) { 12 return head; 13 } 14 ListNode dummy = new ListNode(0), cur = dummy; 15 dummy.next = head; 16 ListNode nodeK, nodeOne, nodeKPlus = null; 17 while ((nodeK = findNodeK(cur, k)) != null) { 18 nodeOne = cur.next; 19 nodeKPlus = nodeK.next; 20 ListNode first = null; 21 ListNode second = nodeOne; 22 while (second != nodeKPlus) { 23 ListNode after = second.next; 24 second.next = first; 25 first = second; 26 second = after; 27 } 28 nodeOne.next = nodeKPlus; 29 cur.next = nodeK; 30 cur = nodeOne; 31 } 32 return dummy.next; 33 } 34 public ListNode findNodeK(ListNode cur, int k) { 35 for (int i = 0; i < k; i++) { 36 if (cur.next == null) { 37 return null; 38 } 39 cur = cur.next; 40 } 41 return cur; 42 } 43 }
Recursing专题
687. Longest Univalue Path
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root. Note: The length of path between two nodes is represented by the number of edges between them. Example 1: Input: 5 / \ 4 5 / \ \ 1 1 5 Output: 2 Example 2: Input: 1 / \ 4 5 / \ \ 4 4 5 Output: 2 Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000.
题意:求一个二叉树中节点值相同的最长路径的长度,路径可以穿过一个节点。
思路:这道题比较难,涉及到的细节很多。递归函数helper用来求以当前节点的节点值相同的单向路径最大长度,也就是说路径不能穿过一个节点。每次helper返回之前,统计以当前节点的节点值相同的双向路径最大长度,也就是说可以穿过一个节点,然后更新全局变量longest。最后递归结束之后,longest的值即为所求。
复杂度分析:时间复杂度O(n),空间复杂度O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public int longest = 0; 12 public int longestUnivaluePath(TreeNode root) { 13 if (root == null) { 14 return 0; 15 } 16 helper(root); 17 return longest; 18 } 19 public int helper(TreeNode root) { 20 int left = 0; 21 if (root.left != null) { 22 left = helper(root.left); 23 } 24 int right = 0; 25 if (root.right != null) { 26 right = helper(root.right); 27 } 28 int l = 0; 29 if (root.left != null && root.val == root.left.val) { 30 l = 1 + left; 31 } 32 int r = 0; 33 if (root.right != null && root.val == root.right.val) { 34 r = 1 + right; 35 } 36 longest = Math.max(longest, l + r); 37 return Math.max(l, r); 38 } 39 }
698. Partition to K Equal Sum Subsets
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k non-empty subsets whose sums are all equal. Example 1: Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 Output: True Explanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums. Note: 1 <= k <= len(nums) <= 16. 0 < nums[i] < 10000.
题意:判断一个整型数组是否能分成K个结果集,这K个结果集里面的元素的总和均相等。
思路:dfs。搜索过程中要记录当前的集合大小cur_size,还需要访问数组visited来记录元素是否已经被访问过,防止重复。
复杂度分析:时间复杂度O(n!),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public boolean canPartitionKSubsets(int[] nums, int k) { 3 if (nums == null || nums.length == 0) { 4 return true; 5 } 6 if (k <= 0) { 7 return false; 8 } 9 int sum = 0; 10 for (int num : nums) { 11 sum += num; 12 } 13 if (sum % k != 0) { 14 return false; 15 } 16 return canPartition(nums, new boolean[nums.length], 0, k, 0, 0, sum / k); 17 } 18 public boolean canPartition(int[] nums, boolean[] visited, int startIndex, int k, int cur_sum, int cur_size, int target) { 19 if (k == 1) { 20 return true; 21 } 22 if (cur_sum == target && cur_size > 0) { 23 return canPartition(nums, visited, 0, k - 1, 0, 0, target); 24 } 25 for (int i = startIndex; i < nums.length; i++) { 26 if (visited[i]) { 27 continue; 28 } 29 visited[i] = true; 30 if (canPartition(nums, visited, i + 1, k, cur_sum + nums[i], cur_size++, target)) { 31 return true; 32 } 33 visited[i] = false; 34 } 35 return false; 36 } 37 }
backtracking专题
经典的计算复杂度的公式 o(构造解的复杂度 * 解的个数)
搜索的时间复杂度:O(答案总数 * 构造每个答案的时间)
举例:Subsets问题,求所有的子集。子集个数一共 2^n,每个集合的平均长度是 O(n) 的,所以时间复杂度为 O(n * 2^n),同理 Permutations 问题的时间复杂度为:O(n * n!)
动态规划的时间复杂度:O(状态总数 * 计算每个状态的时间复杂度)
举例:triangle,数字三角形的最短路径,状态总数约 O(n^2) 个,计算每个状态的时间复杂度为 O(1)——就是求一下 min。所以总的时间复杂度为 O(n^2)
用分治法解决二叉树问题的时间复杂度:O(二叉树节点个数 * 每个节点的计算时间)
举例:二叉树最大深度。二叉树节点个数为 N,每个节点上的计算时间为 O(1)。总的时间复杂度为 O(N)
78. Subsets
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solution set must not contain duplicate subsets. For example, If nums = [1,2,3], a solution is: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
题意:求不含重复元素的数组的全子集
思路:回溯。不用先排序。
复杂度分析:时间复杂度O(n * 2^n),空间复杂度O(2^n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> subsets(int[] nums) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (nums == null) { 5 return results; 6 } 7 backtrack(nums, 0, new ArrayList<Integer>(), results); 8 return results; 9 } 10 public void backtrack(int[] nums, int startIndex, List<Integer> tempList, List<List<Integer>> results) { 11 results.add(new ArrayList<Integer>(tempList)); 12 for (int i = startIndex; i < nums.length; i++) { 13 tempList.add(nums[i]); 14 backtrack(nums, i + 1, tempList, results); 15 tempList.remove(tempList.size() - 1); 16 } 17 } 18 }
90. Subsets II
题意:求含有重复元素的数组的全子集
思路:回溯。先排序,去重处理。
复杂度分析:时间复杂度O(n * 2^n),空间复杂度O(2^n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> subsetsWithDup(int[] nums) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (nums == null) { 5 return results; 6 } 7 Arrays.sort(nums); 8 backtracking(nums, 0, new ArrayList<Integer>(), results); 9 return results; 10 } 11 public void backtracking(int[] nums, int startIndex, List<Integer> tempList, List<List<Integer>> results) { 12 results.add(new ArrayList<Integer>(tempList)); 13 for (int i = startIndex; i < nums.length; i++) { 14 if (i > startIndex && nums[i] == nums[i - 1]) { 15 continue; 16 } 17 tempList.add(nums[i]); 18 backtracking(nums, i + 1, tempList, results); 19 tempList.remove(tempList.size() - 1); 20 } 21 } 22 }
46. Permutations
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a collection of distinct numbers, return all possible permutations. For example, [1,2,3] have the following permutations: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
题意:求不含重复元素的数组的全排列
思路:回溯。不用先排序,为了避免同一元素加入排列多次,要做剪枝处理,也就是要增加一个visited访问数组用来判断哪些元素已经访问过。
复杂度分析:时间复杂度O(n * n!),空间复杂度O(n!)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> permute(int[] nums) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (nums == null || nums.length == 0) { 5 return results; 6 } 7 backtrack(nums, new ArrayList<Integer>(), results); 8 return results; 9 } 10 public void backtrack(int[] nums, List<Integer> tempList, List<List<Integer>> results) { 11 if (tempList.size() == nums.length) { 12 results.add(new ArrayList<Integer>(tempList)); 13 return; 14 } 15 for (int i = 0; i < nums.length; i++) { 16 if (tempList.contains(nums[i])) { 17 continue; 18 } 19 tempList.add(nums[i]); 20 backtrack(nums, tempList, results); 21 tempList.remove(tempList.size() - 1); 22 } 23 } 24 }
47. Permutations II
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a collection of numbers that might contain duplicates, return all possible unique permutations. For example, [1,1,2] have the following unique permutations: [ [1,1,2], [1,2,1], [2,1,1] ]
题意:求含有重复元素的数组的全排列,结果中不能有重复的排列
思路:回溯。先排序,为了避免同一元素加入排列多次,要做剪枝处理,也就是要增加一个visited访问数组用来判断哪些元素已经访问过。为了去重,在判断的时候剪枝一下两种情况:1 当前元素已经访问过 2 当前元素的索引>0并且当前元素值等于前一个元素值并且当前元素的前一个元素没有访问过,标红的这个条件特别容易忘,切记!
复杂度分析:时间复杂度O(n * n!),空间复杂度O(n!)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> permuteUnique(int[] nums) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (nums == null) { 5 return results; 6 } 7 Arrays.sort(nums); 8 backtrack(nums, new boolean[nums.length], new ArrayList<Integer>(), results); 9 return results; 10 } 11 public void backtrack(int[] nums, boolean[] visited, List<Integer> tempList, List<List<Integer>> results) { 12 if (tempList.size() == nums.length) { 13 results.add(new ArrayList<Integer>(tempList)); 14 return; 15 } 16 for (int i = 0; i < nums.length; i++) { 17 if (visited[i] || (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1])) { 18 continue; 19 } 20 visited[i] = true; 21 tempList.add(nums[i]); 22 backtrack(nums, visited, tempList, results); 23 tempList.remove(tempList.size() - 1); 24 visited[i] = false; 25 } 26 } 27 }
39. Combination Sum
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note: All numbers (including target) will be positive integers. The solution set must not contain duplicate combinations. For example, given candidate set [2, 3, 6, 7] and target 7, A solution set is: [ [7], [2, 2, 3] ]
题意:在不含有重复元素的数组中选取元素组合使这些元素的和等于给定值target,一个元素可以被选取多次。
思路:回溯。先排序,然后每次只需要从当前元素开始往后取(包括当前元素)。
复杂度分析:combination sum 这个题目因为有target存在所以并不知道解的个数,但是解的个数最多是子集的个数2^n, 产生每个解的最坏复杂度n,所以我们可以粗略的估计时间复杂度是O(2^n * n)。空间复杂度O(2^n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> combinationSum(int[] candidates, int target) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (candidates == null) { 5 return results; 6 } 7 backtrack(candidates, 0, new ArrayList<Integer>(), 0, target, results); 8 return results; 9 } 10 public void backtrack(int[] candidates, 11 int startIndex, 12 List<Integer> tempList, 13 int sum, 14 int target, 15 List<List<Integer>> results) { 16 if (sum > target) { 17 return; 18 } 19 if (sum == target) { 20 results.add(new ArrayList<Integer>(tempList)); 21 return; 22 } 23 for (int i = startIndex; i < candidates.length; i++) { 24 tempList.add(candidates[i]); 25 backtrack(candidates, i, tempList, sum + candidates[i], target, results); 26 tempList.remove(tempList.size() - 1); 27 } 28 } 29 }
40. Combination Sum II
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. Each number in C may only be used once in the combination. Note: All numbers (including target) will be positive integers. The solution set must not contain duplicate combinations. For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, A solution set is: [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]
题意:在含有重复元素的数组中选取元素组合使这些元素的和等于给定值target,一个元素可以被选取多次。
思路:回溯。先排序,然后每次只需要从当前元素的后一个元素开始往后取(不包括当前元素)
复杂度分析:combination sum 这个题目因为有target存在所以并不知道解的个数,但是解的个数最多是子集的个数2^n, 产生每个解的最坏复杂度n,所以我们可以粗略的估计时间复杂度是O(2^n * n)。空间复杂度O(2^n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> combinationSum2(int[] candidates, int target) { 3 List<List<Integer>> results = new ArrayList<>(); 4 if (candidates == null) { 5 return results; 6 } 7 Arrays.sort(candidates); 8 backtrack(candidates, 0, 0, target, new ArrayList<Integer>(), results); 9 return results; 10 } 11 public void backtrack(int[] candidates, 12 int startIndex, 13 int sum, 14 int target, 15 List<Integer> tempList, 16 List<List<Integer>> results) { 17 if (sum > target) { 18 return; 19 } 20 if (sum == target) { 21 results.add(new ArrayList<Integer>(tempList)); 22 return; 23 } 24 for (int i = startIndex; i < candidates.length; i++) { 25 if (i > startIndex && candidates[i] == candidates[i - 1]) { 26 continue; 27 } 28 tempList.add(candidates[i]); 29 backtrack(candidates, i + 1, sum + candidates[i], target, tempList, results); 30 tempList.remove(tempList.size() - 1); 31 } 32 } 33 }
3. Longest Substring Without Repeating Characters
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a string, find the length of the longest substring without repeating characters. Examples: Given "abcabcbb", the answer is "abc", which the length is 3. Given "bbbbb", the answer is "b", with the length of 1. Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
题意:求字符串的最长不含有重复字符的子串的长度
思路:map存当前字符和位置的映射关系,left和right指向当前非重复串的首尾位置,定义一个max存储最大值,每次放入map前检查map中是否有该字符,如果有,更新left为max{left,map中对应该字符的位置},每次循环都map执行put,求出当前最大不含有重复字符的子串的长度
注意:"abba"这种特殊情况,这也是left为max{left,map中对应该字符的位置}的原因,防止map中过期的索引造成的错误。
复杂度:时间复杂度O(n),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 if (s == null || s.length() == 0) { 4 return 0; 5 } 6 HashMap<Character, Integer> map = new HashMap<>(); 7 int left = 0, right = 0; 8 int max = 0; 9 for ( ; right < s.length(); right++) { 10 if (map.containsKey(s.charAt(right))) { 11 left = Math.max(left, map.get(s.charAt(right)) + 1); 12 } 13 map.put(s.charAt(right), right); 14 max = Math.max(max, right - left + 1); 15 } 16 return max; 17 } 18 }
202. Happy Number
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Write an algorithm to determine if a number is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers. Example: 19 is a happy number 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
思路I:常规思路
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public boolean isHappy(int n) { 3 if (n <= 0) { 4 return false; 5 } 6 Set<Integer> set = new HashSet<>(); 7 while (n != 1) { 8 if (set.contains(n)) { 9 return false; 10 } 11 set.add(n); 12 n = nextNumber(n); 13 } 14 return true; 15 } 16 public int nextNumber(int n) { 17 int sum = 0; 18 while (n != 0) { 19 int number = n % 10; 20 sum += number * number; 21 n = n / 10; 22 } 23 return sum; 24 } 25 }
思路II:考虑到一个数,要么循环直到又重复回到某一个数,如果这个数为1,则为快乐数,如果不为1,则不是快乐数。所以其实可以看成是一个有换的链表,根据环的入口节点值是不是1来判断该数是不是快乐数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public boolean isHappy(int n) { 3 if (n <= 0) { 4 return false; 5 } 6 int slow = n, fast = nextNumber(n); 7 while (slow != fast) { 8 slow = nextNumber(slow); 9 fast = nextNumber(fast); 10 fast = nextNumber(fast); 11 } 12 if (slow == 1) { 13 return true; 14 } 15 return false; 16 } 17 public int nextNumber(int n) { 18 int sum = 0; 19 while (n != 0) { 20 int number = n % 10; 21 sum += number * number; 22 n = n / 10; 23 } 24 return sum; 25 } 26 }
190. Reverse Bits
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Reverse bits of a given 32 bits unsigned integer. 2 3 For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000). 4 5 Follow up: 6 If this function is called many times, how would you optimize it?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Solution { 2 // you need treat n as an unsigned value 3 public int reverseBits(int n) { 4 if (n == 0) { 5 return 0; 6 } 7 int result = 0; 8 for (int i = 0; i < 32; i++) { 9 result = result << 1; 10 if ((n & 1) != 0) { 11 result++; 12 } 13 n = n >> 1; 14 } 15 return result; 16 } 17 }
28. Implement strStr()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Implement strStr(). Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. Example 1: Input: haystack = "hello", needle = "ll" Output: 2 Example 2: Input: haystack = "aaaaa", needle = "bba" Output: -1
思路:i和j指针,不需要指定上边界
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int strStr(String haystack, String needle) { 3 if (haystack == null || needle == null) { 4 return -1; 5 } 6 for (int i = 0; ; i++) { 7 for (int j = 0; ; j++) { 8 if (j == needle.length()) { 9 return i; 10 } 11 if (i + j == haystack.length()) { 12 return -1; 13 } 14 if (haystack.charAt(i + j) != needle.charAt(j)) { 15 break; 16 } 17 } 18 } 19 } 20 }
204. Count Primes
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Description:
Count the number of prime numbers less than a non-negative number, n.
题意:求小于n的素数的个数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int countPrimes(int n) { 3 if (n <= 2) { 4 return 0; 5 } 6 boolean[] notPrime = new boolean[n]; 7 int count = 0; 8 for (int i = 2; i < n; i++) { 9 if (!notPrime[i]) { 10 count++; 11 for (int j = 2; i * j < n; j++) { 12 notPrime[i * j] = true; 13 } 14 } 15 } 16 return count; 17 } 18 }
22. Generate Parentheses
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: [ "((()))", "(()())", "(())()", "()(())", "()()()" ]
思路:backtracking,时间复杂度符合卡特兰数,为O(n!),空间复杂度为O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<String> generateParenthesis(int n) { 3 List<String> result = new ArrayList<>(); 4 helper(result, "", n, n); 5 return result; 6 } 7 public void helper(List<String> result, String str, int left, int right) { 8 if (left > right) { 9 return; 10 } 11 if (left == 0 && right == 0) { 12 result.add(str); 13 return; 14 } 15 if (left > 0) { 16 helper(result, str + "(", left - 1, right); 17 } 18 if (right > 0) { 19 helper(result, str + ")", left, right - 1); 20 } 21 } 22 }
384. Shuffle an Array
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Shuffle a set of numbers without duplicates. Example: // Init an array with set 1, 2, and 3. int[] nums = {1,2,3}; Solution solution = new Solution(nums); // Shuffle the array [1,2,3] and return its result. Any permutation of [1,2,3] must equally likely to be returned. solution.shuffle(); // Resets the array back to its original configuration [1,2,3]. solution.reset(); // Returns the random shuffling of array [1,2,3]. solution.shuffle();
思路:洗牌算法。对于任意位置j(j从1开始,因为没必要从0开始),取一个【0,j】的随机数,然后交换这两个位置的数,然后j从1遍历到nums.length即可。
时间复杂度O(n),空间复杂度O(1)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 3 private int[] nums; 4 Random random; 5 6 public Solution(int[] nums) { 7 this.nums = nums; 8 random = new Random(); 9 } 10 11 /** Resets the array to its original configuration and return it. */ 12 public int[] reset() { 13 return nums; 14 } 15 16 /** Returns a random shuffling of the array. */ 17 public int[] shuffle() { 18 if (nums == null) { 19 return nums; 20 } 21 int[] clone = nums.clone(); 22 for (int i = 1; i < clone.length; i++) { 23 int j = random.nextInt(i + 1); 24 swap(clone, j, i); 25 } 26 return clone; 27 } 28 29 private void swap(int[] nums, int i, int j) { 30 int temp = nums[i]; 31 nums[i] = nums[j]; 32 nums[j] = temp; 33 } 34 } 35 36 /** 37 * Your Solution object will be instantiated and called as such: 38 * Solution obj = new Solution(nums); 39 * int[] param_1 = obj.reset(); 40 * int[] param_2 = obj.shuffle(); 41 */
46. Permutations
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a collection of distinct numbers, return all possible permutations. For example, [1,2,3] have the following permutations: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
思路:backtracking
时间复杂度:O(n * n!),空间复杂度O(n),可以加一个set来优化时间复杂度为O(n!)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> permute(int[] nums) { 3 List<List<Integer>> result = new ArrayList<>(); 4 if (nums == null || nums.length == 0) { 5 return result; 6 } 7 helper(result, new ArrayList<Integer>(), nums); 8 return result; 9 } 10 private void helper(List<List<Integer>> result, List<Integer> tempList, int[] nums) { 11 if (tempList.size() == nums.length) { 12 result.add(new ArrayList<Integer>(tempList)); 13 return; 14 } 15 for (int i = 0; i < nums.length; i++) { 16 if (tempList.contains(nums[i])) { 17 continue; 18 } 19 tempList.add(nums[i]); 20 helper(result, tempList, nums); 21 tempList.remove(tempList.size() - 1); 22 } 23 } 24 }
378. Kth Smallest Element in a Sorted Matrix
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element. Example: matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15] ], k = 8, return 13. Note: You may assume k is always valid, 1 ≤ k ≤ n2.
思路I:最小堆。时间复杂度O(nlgn),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int kthSmallest(int[][] matrix, int k) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return 0; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 if (k < 1 || k > n * m) { 8 return 0; 9 } 10 PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>(n, new Comparator<Tuple>(){ 11 @Override 12 public int compare(Tuple a, Tuple b) { 13 return a.val - b.val; 14 } 15 }); 16 for (int i = 0; i < m; i++) { 17 pq.offer(new Tuple(0, i, matrix[0][i])); 18 } 19 for (int i = 0; i < k - 1; i++) { 20 Tuple tuple = pq.poll(); 21 if (tuple.x < n - 1) { 22 pq.offer(new Tuple(tuple.x + 1, tuple.y, matrix[tuple.x + 1][tuple.y])); 23 } 24 } 25 return pq.poll().val; 26 } 27 } 28 class Tuple { 29 int x; 30 int y; 31 int val; 32 public Tuple(int x, int y, int val) { 33 this.x = x; 34 this.y = y; 35 this.val = val; 36 } 37 }
思路II:二分。注意统计的是比target值小的元素个数,而不是小于等于target值得个数。时间复杂度O(nlg(max - min)),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int kthSmallest(int[][] matrix, int k) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return 0; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 if (k < 1 || k > n * m) { 8 return 0; 9 } 10 int start = matrix[0][0], end = matrix[n - 1][m - 1]; 11 while (start + 1 < end) { 12 int mid = start + (end - start) / 2; 13 int num = count(matrix, mid); 14 if (num < k) { 15 start = mid; 16 } else { 17 end = mid; 18 } 19 } 20 if (count(matrix, end) <= k - 1) { 21 return end; 22 } 23 return start; 24 } 25 private int count(int[][] matrix, int target) { 26 int n = matrix.length, m = matrix[0].length; 27 int result = 0; 28 int i = n - 1, j = 0; 29 while (i >= 0 && j < m) { 30 if (matrix[i][j] >= target) { 31 i--; 32 } else { 33 result += i + 1; 34 j++; 35 } 36 } 37 return result; 38 } 39 }
78. Subsets
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solution set must not contain duplicate subsets. For example, If nums = [1,2,3], a solution is: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
思路:backtracking
时间复杂度O(n!),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<Integer>> subsets(int[] nums) { 3 List<List<Integer>> result = new ArrayList<>(); 4 if (nums == null || nums.length == 0) { 5 return result; 6 } 7 helper(result, new ArrayList<Integer>(), nums, 0); 8 return result; 9 } 10 private void helper(List<List<Integer>> result, List<Integer> tempList, int[] nums, int startIndex) { 11 result.add(new ArrayList<Integer>(tempList)); 12 if (startIndex == nums.length) { 13 return; 14 } 15 for (int i = startIndex; i < nums.length; i++) { 16 tempList.add(nums[i]); 17 helper(result, tempList, nums, i + 1); 18 tempList.remove(tempList.size() - 1); 19 } 20 } 21 }
287. Find the Duplicate Number
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. Note: You must not modify the array (assume the array is read only). You must use only constant, O(1) extra space. Your runtime complexity should be less than O(n2). There is only one duplicate number in the array, but it could be repeated more than once.
思路:二分答案,然后数小于等于mid的个数,如果这个个数比mid小,start=mid,否则end=mid
时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int findDuplicate(int[] nums) { 3 if (nums == null || nums.length <= 1) { 4 return 0; 5 } 6 int start = 1, end = nums.length - 1; 7 while (start + 1 < end) { 8 int mid = start + (end - start) / 2; 9 if (count(nums, mid) <= mid) { 10 start = mid; 11 } else { 12 end = mid; 13 } 14 } 15 if (count(nums, start) <= start) { 16 return end; 17 } 18 return start; 19 } 20 private int count(int[] nums, int target) { 21 int result = 0; 22 for (int i = 0; i < nums.length; i++) { 23 if (nums[i] <= target) { 24 result++; 25 } 26 } 27 return result; 28 } 29 }
341. Flatten Nested List Iterator
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a nested list of integers, implement an iterator to flatten it. Each element is either an integer, or a list -- whose elements may also be integers or other lists. Example 1: Given the list [[1,1],2,[1,1]], By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1]. Example 2: Given the list [1,[4,[6]]], By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6].
思路:stack存储,加入的时候从后往前
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * // This is the interface that allows for creating nested lists. 3 * // You should not implement it, or speculate about its implementation 4 * public interface NestedInteger { 5 * 6 * // @return true if this NestedInteger holds a single integer, rather than a nested list. 7 * public boolean isInteger(); 8 * 9 * // @return the single integer that this NestedInteger holds, if it holds a single integer 10 * // Return null if this NestedInteger holds a nested list 11 * public Integer getInteger(); 12 * 13 * // @return the nested list that this NestedInteger holds, if it holds a nested list 14 * // Return null if this NestedInteger holds a single integer 15 * public List<NestedInteger> getList(); 16 * } 17 */ 18 public class NestedIterator implements Iterator<Integer> { 19 20 Stack<NestedInteger> stack; 21 22 public NestedIterator(List<NestedInteger> nestedList) { 23 stack = new Stack<NestedInteger>(); 24 for (int i = nestedList.size() - 1; i >= 0; i--) { 25 stack.push(nestedList.get(i)); 26 } 27 } 28 29 @Override 30 public Integer next() { 31 if (!hasNext()) { 32 return null; 33 } 34 return stack.pop().getInteger(); 35 } 36 37 @Override 38 public boolean hasNext() { 39 while (!stack.isEmpty()) { 40 NestedInteger nestedInteger = stack.peek(); 41 if (nestedInteger.isInteger()) { 42 return true; 43 } 44 stack.pop(); 45 for (int i = nestedInteger.getList().size() - 1; i >= 0; i--) { 46 stack.push(nestedInteger.getList().get(i)); 47 } 48 } 49 return false; 50 } 51 } 52 53 /** 54 * Your NestedIterator object will be instantiated and called as such: 55 * NestedIterator i = new NestedIterator(nestedList); 56 * while (i.hasNext()) v[f()] = i.next(); 57 */
48. Rotate Image
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). Note: You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation. Example 1: Given input matrix = [ [1,2,3], [4,5,6], [7,8,9] ], rotate the input matrix in-place such that it becomes: [ [7,4,1], [8,5,2], [9,6,3] ] Example 2: Given input matrix = [ [ 5, 1, 9,11], [ 2, 4, 8,10], [13, 3, 6, 7], [15,14,12,16] ], rotate the input matrix in-place such that it becomes: [ [15,13, 2, 5], [14, 3, 4, 1], [12, 6, 8, 9], [16, 7,10,11] ]
思路:
顺时针旋转90度:先对称上下行元素逐一交换,然后按照左45度对角线对称交换元素
逆时针旋转90度:先对称左右列元素逐一交换,然后按照左45度对角线对称交换元素
时间复杂度O(n * m),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public void rotate(int[][] matrix) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 for (int i = 0; i < n / 2; i++) { 8 for (int j = 0; j < m; j++) { 9 int temp = matrix[i][j]; 10 matrix[i][j] = matrix[n - 1 - i][j]; 11 matrix[n - 1 - i][j] = temp; 12 } 13 } 14 for (int i = 1; i < n; i++) { 15 for (int j = 0; j < i; j++) { 16 int temp = matrix[i][j]; 17 matrix[i][j] = matrix[j][i]; 18 matrix[j][i] = temp; 19 } 20 } 21 } 22 }
380. Insert Delete GetRandom O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Design a data structure that supports all following operations in average O(1) time. insert(val): Inserts an item val to the set if not already present. remove(val): Removes an item val from the set if present. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. Example: // Init an empty set. RandomizedSet randomSet = new RandomizedSet(); // Inserts 1 to the set. Returns true as 1 was inserted successfully. randomSet.insert(1); // Returns false as 2 does not exist in the set. randomSet.remove(2); // Inserts 2 to the set, returns true. Set now contains [1,2]. randomSet.insert(2); // getRandom should return either 1 or 2 randomly. randomSet.getRandom(); // Removes 1 from the set, returns true. Set now contains [2]. randomSet.remove(1); // 2 was already in the set, so return false. randomSet.insert(2); // Since 2 is the only number in the set, getRandom always return 2. randomSet.getRandom();
思路:List + HashMap + Random,List存储非重复元素的索引和值的映射,HashMap存储值和索引的映射,便于remove元素时在O(1)时间内定位到这个元素的索引位置。remove元素时,如果元素所在list中的index不是最后一个,则将该位置的元素设置为最后一个索引元素,然后删除。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class RandomizedSet { 2 3 List<Integer> list; 4 Map<Integer, Integer> map; 5 Random random; 6 7 /** Initialize your data structure here. */ 8 public RandomizedSet() { 9 list = new ArrayList<Integer>(); 10 map = new HashMap<Integer, Integer>(); 11 random = new Random(); 12 } 13 14 /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ 15 public boolean insert(int val) { 16 if (map.containsKey(val)) { 17 return false; 18 } 19 list.add(val); 20 map.put(val, list.size() - 1); 21 return true; 22 } 23 24 /** Removes a value from the set. Returns true if the set contained the specified element. */ 25 public boolean remove(int val) { 26 if (!map.containsKey(val)) { 27 return false; 28 } 29 int index = map.get(val); 30 if (index != list.size() - 1) { 31 list.set(index, list.get(list.size() - 1)); 32 map.put(list.get(list.size() - 1), index); 33 } 34 list.remove(list.size() - 1); 35 map.remove(val); 36 return true; 37 } 38 39 /** Get a random element from the set. */ 40 public int getRandom() { 41 int index = random.nextInt(list.size()); 42 return list.get(index); 43 } 44 } 45 46 /** 47 * Your RandomizedSet object will be instantiated and called as such: 48 * RandomizedSet obj = new RandomizedSet(); 49 * boolean param_1 = obj.insert(val); 50 * boolean param_2 = obj.remove(val); 51 * int param_3 = obj.getRandom(); 52 */
334. Increasing Triplet Subsequence
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array. Formally the function should: Return true if there exists i, j, k such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false. Your algorithm should run in O(n) time complexity and O(1) space complexity. Examples: Given [1, 2, 3, 4, 5], return true. Given [5, 4, 3, 2, 1], return false.
思路:存储一个最小值min和一个第二小值secondMin,遍历数组,如果<=min,更新min,如果小于等于secondMin,更新secondMin,否则,说明找到了一个不重复的三元组满足从小到大排序。
时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public boolean increasingTriplet(int[] nums) { 3 if (nums == null || nums.length < 3) { 4 return false; 5 } 6 int min = Integer.MAX_VALUE, secondMin = Integer.MAX_VALUE; 7 for (int i = 0; i < nums.length; i++) { 8 if (nums[i] <= min) { 9 min = nums[i]; 10 } else if (nums[i] <= secondMin) { 11 secondMin = nums[i]; 12 } else { 13 return true; 14 } 15 } 16 return false; 17 } 18 }
300. Longest Increasing Subsequence
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an unsorted array of integers, find the length of longest increasing subsequence. For example, Given [10, 9, 2, 5, 3, 7, 101, 18], The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length. Your algorithm should run in O(n2) complexity. Follow up: Could you improve it to O(n log n) time complexity?
思路I:动态规划,dp[i]表示以i结尾的最长子序列的长度,枚举0 ~ i - 1的位置来更新dp[i],最后的结果为dp[i]中的最大值
时间复杂度O(n ^ 2),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int lengthOfLIS(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int[] dp = new int[nums.length]; 7 int max = 0; 8 for (int i = 0; i < nums.length; i++) { 9 dp[i] = 1; 10 for (int j = 0; j < i; j++) { 11 if (nums[j] < nums[i]) { 12 dp[i] = Math.max(dp[i], dp[j] + 1); 13 } 14 } 15 max = Math.max(max, dp[i]); 16 } 17 return max; 18 } 19 }
思路II:dp数组存储元素值最小的最长的递增子序列,从位置1开始遍历数组每一个元素,binary search找该元素值在dp数组中插入的位置,然后覆盖,如果插入位置为len,则len++。
时间复杂度O(nlgn),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int lengthOfLIS(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int[] dp = new int[nums.length]; 7 dp[0] = nums[0]; 8 int len = 1; 9 for (int i = 1; i < nums.length; i++) { 10 // 第二种写法 11 // if (nums[i] > dp[len - 1]) { 12 // dp[len++] = nums[i]; 13 // } else { 14 // int pos = searchPosition(dp, len, nums[i]); 15 // dp[pos] = nums[i]; 16 // } 17 // 第一种写法 18 int pos = searchPosition(dp, len, nums[i]); 19 dp[pos] = nums[i];; 20 if (pos == len) { 21 len++; 22 } 23 } 24 return len; 25 } 26 private int searchPosition(int[] dp, int len, int target) { 27 int start = 0, end = len - 1; 28 while (start + 1 < end) { 29 int mid = start + (end - start) / 2; 30 if (dp[mid] == target) { 31 return mid; 32 } else if (dp[mid] < target) { 33 start = mid; 34 } else { 35 end = mid; 36 } 37 } 38 if (target <= dp[start]) { 39 return start; 40 } 41 if (target <= dp[end]) { 42 return end; 43 } 44 return end + 1; 45 } 46 }
75. Sort Colors
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. Note: You are not suppose to use the library's sort function for this problem.
思路:left指针指向下一个0的末尾,排在首端,right指向下一个2的位置,排在末端,当遍历的当前元素(位置为i)为0则交换i和left,left++,i++;为1则i++;为2则交换i和right,right--,这个时候交换之后i位置上的元素可能为0,所以还需要在下一次循环中再判断,所以不执行i++操作。
时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public void sortColors(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return; 5 } 6 int left = 0, right = nums.length - 1; 7 int i = 0; 8 while (i <= right) { 9 if (nums[i] == 0) { 10 swap(nums, i, left); 11 left++; 12 i++; 13 } else if (nums[i] == 1) { 14 i++; 15 } else { 16 swap(nums, i, right); 17 right--; 18 } 19 } 20 } 21 private void swap(int[] nums, int i, int j) { 22 int temp = nums[i]; 23 nums[i] = nums[j]; 24 nums[j] = temp; 25 } 26 }
405. Convert a Number to Hexadecimal
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s complement method is used. Note: All letters in hexadecimal (a-f) must be in lowercase. The hexadecimal string must not contain extra leading 0s. If the number is zero, it is represented by a single zero character '0'; otherwise, the first character in the hexadecimal string will not be the zero character. The given number is guaranteed to fit within the range of a 32-bit signed integer. You must not use any method provided by the library which converts/formats the number to hex directly. Example 1: Input: 26 Output: "1a" Example 2: Input: -1 Output: "ffffffff"
思路:建立一个"0123456789abcdef"串用来索引十六进制的值,每次将num的低四位和oxf做与运算得到低四位的值,根据这个值索引到对应的十六进制值,然后num右移四位继续循环,直到num为0位置。
注意:当num为0时的特殊情况的处理,否则输出为"",造成错误。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public String toHex(int num) { 3 // num为0一定要提前判断 4 if (num == 0) { 5 return "0"; 6 } 7 String hash = "0123456789abcdef"; 8 StringBuilder sb = new StringBuilder(); 9 while (num != 0) { 10 int index = num & 0xf; 11 sb.append(hash.charAt(index)); 12 num = num >>> 4; 13 } 14 return sb.reverse().toString(); 15 } 16 }
162. Find Peak Element
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
A peak element is an element that is greater than its neighbors. Given an input array where num[i] ≠ num[i+1], find a peak element and return its index. The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. You may imagine that num[-1] = num[n] = -∞. For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
思路I:O(n)暴力解法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int findPeakElement(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return -1; 5 } 6 for (int i = 0; i < nums.length; i++) { 7 if (((i - 1 < 0) || nums[i - 1] < nums[i]) && ((i + 1 == nums.length) || nums[i + 1] < nums[i])) { 8 return i; 9 } 10 } 11 return -1; 12 } 13 }
思路II:O(lgn)二分,根据nums[mid]和nums[mid - 1]的大小关系或者nums[mid]和nums[mid + 1]的大小关系保留有解的那部分。因为nums[-1]和nums[len]为负无穷,若nums[i] < nums[i - 1]则左边一定有解,因为如果nums[i - 2] < nums[i - 1]则i - 1就是解,如果nums[i - 2] > nums[i - 1]则继续往左边找,因为nums[-1]为负无穷,最后位置0一定为peak解(如果前面的都没解的话)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int findPeakElement(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return -1; 5 } 6 int start = 0, end = nums.length - 1; 7 while (start + 1 < end) { 8 int mid = start + (end - start) / 2; 9 if (nums[mid] > nums[mid - 1]) { 10 start = mid; 11 } else { 12 end = mid; 13 } 14 } 15 if (nums[start] > nums[end]) { 16 return start; 17 } 18 return end; 19 } 20 }
49. Group Anagrams
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an array of strings, group anagrams together. For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], Return: [ ["ate", "eat","tea"], ["nat","tan"], ["bat"] ] Note: All inputs will be in lower-case.
思路:将每个字符串按照自然顺序排好序的string作为key,以跟这个key有相同的同字母异序串的List集合为value。时间复杂度O(n * len * loglen),空间复杂度O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<String>> groupAnagrams(String[] strs) { 3 List<List<String>> result = new ArrayList<>(); 4 if (strs == null || strs.length == 0) { 5 return result; 6 } 7 Map<String, List<String>> map = new HashMap<>(); 8 for (int i = 0; i < strs.length; i++) { 9 String str = getBaseString(strs[i]); 10 if (!map.containsKey(str)) { 11 map.put(str, new ArrayList<String>()); 12 map.get(str).add(strs[i]); 13 } else { 14 map.get(str).add(strs[i]); 15 } 16 } 17 for (String str : map.keySet()) { 18 result.add(map.get(str)); 19 } 20 return result; 21 } 22 private String getBaseString(String str) { 23 char[] c = str.toCharArray(); 24 Arrays.sort(c); 25 return new String(c); 26 } 27 }
289. Game of Life
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970." Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article): Any live cell with fewer than two live neighbors dies, as if caused by under-population. Any live cell with two or three live neighbors lives on to the next generation. Any live cell with more than three live neighbors dies, as if by over-population.. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. Write a function to compute the next state (after one update) of the board given its current state. Follow up: Could you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells. In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?
思路:由于要求空间复杂度为O(1),所以不能开辟一个新的二维数组来存储下一个状态的信息,我们用第二位bit来代替。第一位bit存储当前状态,第二位bit存储下一个状态。然后每次数该位置周围的1的个数,根据这个个数来更新第二位bit位。最后将所有位置的元素右移一位,将第二位bit的值赋值给第一位,即将第二位的bit代替第一位的bit,即下一个状态代替当前状态。
时间复杂度o(n * m),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public void gameOfLife(int[][] board) { 3 if (board == null || board.length == 0 || board[0].length == 0) { 4 return; 5 } 6 int n = board.length, m = board[0].length; 7 for (int i = 0; i < n; i++) { 8 for (int j = 0; j < m; j++) { 9 int count = countNeighbor(board, i, j); 10 if (board[i][j] == 1) { 11 if (count == 2 || count == 3) { 12 board[i][j] += 2; 13 } 14 } else { 15 if (count == 3) { 16 board[i][j] += 2; 17 } 18 } 19 } 20 } 21 for (int i = 0; i < n; i++) { 22 for (int j = 0; j < m; j++) { 23 board[i][j] = board[i][j] >>> 1; 24 } 25 } 26 } 27 private int countNeighbor(int[][] board, int i, int j) { 28 int count = 0; 29 int n = board.length, m = board[0].length; 30 for (int row = Math.max(i - 1, 0); row <= Math.min(i + 1, n - 1); row++) { 31 for (int col = Math.max(j - 1, 0); col <= Math.min(j + 1, m - 1); col++) { 32 if (row == i && col == j) { 33 continue; 34 } 35 if ((board[row][col] & 1) == 1) { 36 count++; 37 } 38 } 39 } 40 return count; 41 } 42 }
11. Container With Most Water
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
思路:从数组的首尾位置开始,使得宽度尽可能大,然后高度取两个位置对应高度的较小值,然后哪个位置的高度低就移动哪个位置(宽度虽然减少,但是高度尽可能高以使得容纳的水更多)
时间复杂度O(n),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int maxArea(int[] height) { 3 if (height == null || height.length <= 1) { 4 return 0; 5 } 6 int max = 0; 7 int left = 0, right = height.length - 1; 8 while (left < right) { 9 max = Math.max(max, (right - left) * Math.min(height[left], height[right])); 10 if (height[left] < height[right]) { 11 left++; 12 } else { 13 right--; 14 } 15 } 16 return max; 17 } 18 }
73. Set Matrix Zeroes
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
思路I:naive解法,时间复杂度:O(n * m),空间复杂度O(max{n,m})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public void setZeroes(int[][] matrix) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 List<Integer> rows = new ArrayList<>(); 8 List<Integer> cols = new ArrayList<>(); 9 for (int i = 0; i < n; i++) { 10 for (int j = 0; j < m; j++) { 11 if (matrix[i][j] == 0) { 12 rows.add(i); 13 cols.add(j); 14 } 15 } 16 } 17 for (int i = 0; i < rows.size(); i++) { 18 for (int j = 0; j < m; j++) { 19 matrix[rows.get(i)][j] = 0; 20 } 21 } 22 for (int i = 0; i < cols.size(); i++) { 23 for (int j = 0; j < n; j++) { 24 matrix[j][cols.get(i)] = 0; 25 } 26 } 27 } 28 29 }
思路II:如果matrix[i][j]为0,则当前行首和列首置为0,然后两个标志row和col分别代表第0行是否有0,第0列是否有0。时间复杂度:O(n * m),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public void setZeroes(int[][] matrix) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 boolean row = false, col = false; 8 for (int i = 0; i < n; i++) { 9 for (int j = 0; j < m; j++) { 10 if (matrix[i][j] == 0) { 11 matrix[i][0] = 0; 12 matrix[0][j] = 0; 13 if (i == 0) { 14 row = true; 15 } 16 if (j == 0) { 17 col = true; 18 } 19 } 20 } 21 } 22 for (int i = 1; i < n; i++) { 23 if (matrix[i][0] == 0) { 24 for (int j = 1; j < m; j++) { 25 matrix[i][j] = 0; 26 } 27 } 28 } 29 for (int j = 1; j < m; j++) { 30 if(matrix[0][j] == 0) { 31 for (int i = 1; i < n; i++) { 32 matrix[i][j] = 0; 33 } 34 } 35 } 36 if (row) { 37 for (int j = 0; j < m; j++) { 38 matrix[0][j] = 0; 39 } 40 } 41 if (col) { 42 for (int i = 0; i < n; i++) { 43 matrix[i][0] = 0; 44 } 45 } 46 } 47 }
131. Palindrome Partitioning
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. For example, given s = "aab", Return [ ["aa","b"], ["a","a","b"] ]
思路:对每一个开始位置,逐一+1分割串,只有当前子串为回文串才继续向下回溯。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<List<String>> partition(String s) { 3 List<List<String>> result = new ArrayList<>(); 4 if (s == null || s.length() == 0) { 5 return result; 6 } 7 helper(s, 0, new ArrayList<String>(), result); 8 return result; 9 } 10 private void helper(String s, int startIndex, List<String> tempList, List<List<String>> result) { 11 if (startIndex == s.length()) { 12 result.add(new ArrayList<String>(tempList)); 13 return; 14 } 15 for (int i = startIndex; i < s.length(); i++) { 16 String partition = s.substring(startIndex, i + 1); 17 if (isPalindrome(partition)) { 18 tempList.add(partition); 19 helper(s, i + 1, tempList, result); 20 tempList.remove(tempList.size() - 1); 21 } 22 } 23 } 24 private boolean isPalindrome(String s) { 25 if (s == null || s.length() == 0) { 26 return true; 27 } 28 int left = 0, right = s.length() - 1; 29 while (left < right) { 30 if (s.charAt(left) != s.charAt(right)) { 31 return false; 32 } 33 left++; 34 right--; 35 } 36 return true; 37 } 38 }
33. Search in Rotated Sorted Array
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). You are given a target value to search. If found in the array return its index, otherwise return -1. You may assume no duplicate exists in the array.
思路:二分。先根据nums[mid]和nums[start]确定mid在哪一个上升区间,然后再判断target是否在nums[start] - nums[mid]或者nums[mid] - nums[end]之中来确定target在哪一半部分。
时间复杂度O(lgn),空间复杂度O(1)
81. Search in Rotated Sorted Array II
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this affect the run-time complexity? How and why? Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Write a function to determine if a given target is in the array. The array may contain duplicates.
思路:同上。注意这道题可以含有重复的元素,所以多一步判断,就是当nums[mid] == nums[start]时,我们无法判断target在哪一半部分,所以此时我们只需要start++即可。
时间复杂度:平均O(lgn),最坏O(n)(所有元素相同)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public boolean search(int[] nums, int target) { 3 if (nums == null || nums.length == 0) { 4 return false; 5 } 6 int start = 0, end = nums.length - 1; 7 while (start + 1 < end) { 8 int mid = start + (end - start) / 2; 9 if (nums[mid] == nums[start]) { 10 start++; 11 } else if (nums[mid] > nums[start]) { 12 if (target >= nums[start] && target <= nums[mid]) { 13 end = mid; 14 } else { 15 start = mid; 16 } 17 } else { 18 if (target >= nums[mid] && target <= nums[end]) { 19 start = mid; 20 } else { 21 end = mid; 22 } 23 } 24 } 25 if (nums[start] == target) { 26 return true; 27 } 28 if (nums[end] == target) { 29 return true; 30 } 31 return false; 32 } 33 }
56. Merge Intervals
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8,10],[15,18], return [1,6],[8,10],[15,18].
思路:对Interval按照start属性排序,然后用start和end分别记录当前间隔的开始位置和结束位置,每当遍历一个Interval,就看当前Interval的start是否大于end,如果大于,说明没有重叠,则将start - end的Interval加入结果集中;否则,更新end值为max{end,interval.start}。然后继续遍历下一个Interval
时间复杂度O(nlgn),空间复杂度O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * Definition for an interval. * public class Interval { * int start; * int end; * Interval() { start = 0; end = 0; } * Interval(int s, int e) { start = s; end = e; } * } */ class Solution { public List<Interval> merge(List<Interval> intervals) { List<Interval> result = new ArrayList<>(); if (intervals == null || intervals.size() == 0) { return result; } Collections.sort(intervals, new Comparator<Interval>() { public int compare(Interval a, Interval b) { return a.start - b.start; } }); int start = intervals.get(0).start; int end = intervals.get(0).end; for (int i = 1; i < intervals.size(); i++) { if (intervals.get(i).start > end) { result.add(new Interval(start, end)); start = intervals.get(i).start; end = intervals.get(i).end; } else { end = Math.max(end, intervals.get(i).end); } } result.add(new Interval(start, end)); return result; } }
227. Basic Calculator II
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Implement a basic calculator to evaluate a simple expression string. The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero. You may assume that the given expression is always valid. Some examples: "3+2*2" = 7 " 3/2 " = 1 " 3+5 / 2 " = 5 Note: Do not use the eval built-in library function.
思路:由于存在运算优先级,我们采取的措施是使用一个栈保存数字,如果该数字之前的符号是加或减,那么把当前数字压入栈中,注意如果是减号,则加入当前数字的相反数,因为减法相当于加上一个相反数。如果之前的符号是乘或除,那么从栈顶取出一个数字和当前数字进行乘或除的运算,再把结果压入栈中,那么完成一遍遍历后,所有的乘或除都运算完了,再把栈中所有的数字都加起来就是最终结果了。
time:O(len) space:O(len)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int calculate(String s) { 3 if (s == null) { 4 return 0; 5 } 6 s = s.trim(); 7 if (s.length() == 0) { 8 return 0; 9 } 10 int num = 0; 11 char sign = '+'; 12 Stack<Integer> stack = new Stack<>(); 13 char[] c = s.toCharArray(); 14 for (int i = 0; i < c.length; i++) { 15 if (c[i] == ' ') { 16 continue; 17 } 18 if (Character.isDigit(c[i])) { 19 num = num * 10 + (c[i] - '0'); 20 } 21 if (c[i] == '+' || c[i] == '-' || c[i] == '*'|| c[i] == '/' || i == c.length - 1) { 22 if (sign == '+') { 23 stack.push(num); 24 } else if (sign == '-') { 25 stack.push(-num); 26 } else if (sign == '*') { 27 stack.push(stack.pop() * num); 28 } else { 29 stack.push(stack.pop() / num); 30 } 31 sign = c[i]; 32 num = 0; 33 } 34 } 35 int result = 0; 36 while (!stack.isEmpty()) { 37 result += stack.pop(); 38 } 39 return result; 40 } 41 }
134. Gas Station
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations. Return the starting gas station's index if you can travel around the circuit once, otherwise return -1. Note: The solution is guaranteed to be unique.
思路:我们首先要知道能走完整个环的前提是gas的总量要大于cost的总量,这样才会有起点的存在。假设开始设置起点start = 0, 并从这里出发,如果当前的gas值大于cost值,就可以继续前进,此时到下一个站点,剩余的gas加上当前的gas再减去cost,看是否大于0,若大于0,则继续前进。当到达某一站点时,若这个值小于0了,则说明从起点到这个点中间的任何一个点都不能作为起点,则把起点设为下一个点,继续遍历。当遍历完整个环时,当前保存的起点即为所求。
time:O(n),space:O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int canCompleteCircuit(int[] gas, int[] cost) { 3 if (gas == null || gas.length == 0 || cost == null || cost.length == 0) { 4 return -1; 5 } 6 int sum = 0, start = 0, total = 0; 7 for (int i = 0; i < gas.length; i++) { 8 sum += gas[i] - cost[i]; 9 total += gas[i] - cost[i]; 10 if (sum < 0) { 11 start = i + 1; 12 sum = 0; 13 } 14 } 15 if (total < 0) { 16 return -1; 17 } 18 return start; 19 } 20 }
150. Evaluate Reverse Polish Notation
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. Some examples: ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
1.前缀表示法,也叫波特兰表示法,操作符放在前面,如:a+b*(c+d)写成+a*b+cd。前缀表达式是自右向左扫描,你看当扫到“+”的时候则先把扫描的两个操作数拿出来运算(c+d);当碰到“*”时则运算b*(c+d);碰到“+”是a+b*(c+d)。可用栈实现。
2.后缀表示法,也叫逆波特兰表示法,操作符放在后面,如:a+b*(c+d)写成abcd+*+。后缀表达式恰恰相反是从左向右扫描,后缀表达式abcd+*+,当扫描到“+”的时候则运算c+d;当扫描到*的时候则运算b*(c+d);当扫描到最后个“+”的时候则运算a+b*(c+d)。可用
栈实现。
time:O(n) space:O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int evalRPN(String[] tokens) { 3 if (tokens == null || tokens.length == 0) { 4 return 0; 5 } 6 Stack<Integer> stack = new Stack<>(); 7 for (int i = 0; i < tokens.length; i++) { 8 if (tokens[i].equals("+")) { 9 stack.push(stack.pop() + stack.pop()); 10 } else if (tokens[i].equals("-")) { 11 int b = stack.pop(); 12 int a = stack.pop(); 13 stack.push(a - b); 14 } else if (tokens[i].equals("*")) { 15 stack.push(stack.pop() * stack.pop()); 16 } else if (tokens[i].equals("/")) { 17 int b = stack.pop(); 18 int a = stack.pop(); 19 stack.push(a / b); 20 } else { 21 stack.push(Integer.parseInt(tokens[i])); 22 } 23 } 24 return stack.pop(); 25 } 26 }
152. Maximum Product Subarray
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Find the contiguous subarray within an array (containing at least one number) which has the largest product. For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6.
思路:dp_max[i]和dp_min[i] 分别表示以当前位置i结尾的子数组乘积的最大值和最小值,最大值最小值在nums[i]、dp_max[i - 1] * nums[i]和dp_min[i - 1] * nums[i]中产生
dp_max[i] = max{ nums[i], dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i] }
dp_min[i] = min( nums[i], dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i]) }
time:O(n) space:O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int maxProduct(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int[] dp_max = new int[nums.length]; 7 int[] dp_min = new int[nums.length]; 8 dp_max[0] = nums[0]; 9 dp_min[0] = nums[0]; 10 int maxProduct = nums[0]; 11 for (int i = 1; i < nums.length; i++) { 12 dp_max[i] = Math.max(nums[i], Math.max(dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i])); 13 dp_min[i] = Math.min(nums[i], Math.min(dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i])); 14 maxProduct = Math.max(maxProduct, dp_max[i]); 15 } 16 return maxProduct; 17 } 18 }
由于只用到了前一个位置的结果,所以我们不需要开辟长度为n的数组,用一个变量代替即可
time:O(n) space:O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int maxProduct(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 0; 5 } 6 int max_pre = nums[0]; 7 int min_pre = nums[0]; 8 int maxProduct = nums[0]; 9 for (int i = 1; i < nums.length; i++) { 10 int max_cur = Math.max(nums[i], Math.max(max_pre * nums[i], min_pre * nums[i])); 11 int min_cur = Math.min(nums[i], Math.min(max_pre * nums[i], min_pre * nums[i])); 12 maxProduct = Math.max(maxProduct, max_cur); 13 max_pre = max_cur; 14 min_pre = min_cur; 15 } 16 return maxProduct; 17 } 18 }
50. Pow(x, n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Implement pow(x, n). Example 1: Input: 2.00000, 10 Output: 1024.00000 Example 2: Input: 2.10000, 3 Output: 9.26100
思路:递归。注意2.00000 -2147483648这个testcase的情况的特殊处理
time:O(lgn) space:O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public double myPow(double x, int n) { 3 if (n == 0) { 4 return 1; 5 } 6 if (n == 1) { 7 return x; 8 } 9 long num = n; 10 if (n < 0) { 11 num = -num; 12 x = 1 / x; 13 } 14 if (n % 2 == 0) { 15 return myPow(x * x, (int) (num / 2)); 16 } 17 return x * myPow(x * x, (int) (num / 2)); 18 } 19 }
98. Validate Binary Search Tree
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys greater than the node's key. Both the left and right subtrees must also be binary search trees. Example 1: 2 / \ 1 3 Binary tree [2,1,3], return true. Example 2: 1 / \ 2 3 Binary tree [1,2,3], return false.
思路I:递归 time:O(n) space:O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isValidBST(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 return helper(root, Long.MIN_VALUE, Long.MAX_VALUE); 16 } 17 private boolean helper(TreeNode root, long min, long max) { 18 if (root == null) { 19 return true; 20 } 21 if (root.val <= min || root.val >= max) { 22 return false; 23 } 24 return helper(root.left, min, root.val) && helper(root.right, root.val, max); 25 } 26 }
思路II:迭代 time:O(n) space:O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public boolean isValidBST(TreeNode root) { 12 if (root == null) { 13 return true; 14 } 15 Stack<TreeNode> stack = new Stack<>(); 16 TreeNode cur = root, pre = null; 17 while (cur != null || !stack.isEmpty()) { 18 while (cur != null) { 19 stack.push(cur); 20 cur = cur.left; 21 } 22 cur = stack.pop(); 23 if (pre != null && cur.val <= pre.val) { 24 return false; 25 } 26 pre = cur; 27 cur = cur.right; 28 } 29 return true; 30 } 31 }
91. Decode Ways
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 Given an encoded message containing digits, determine the total number of ways to decode it. For example, Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). The number of ways decoding "12" is 2.
思路:dp。
dp[i]表示长度为i的字符串的解码方式有多少种
dp[i] = dp[i - 1] (第i个字符有效) + dp[i - 2] (第i-1 ~ i个字符有效)
time:O(n) space:O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int numDecodings(String s) { 3 if (s == null || s.length() == 0) { 4 return 0; 5 } 6 int[] dp = new int[s.length() + 1]; 7 dp[0] = 1; 8 dp[1] = s.charAt(0) == '0' ? 0 : 1; 9 for (int i = 2; i <= s.length(); i++) { 10 int first = Integer.parseInt(s.substring(i - 1 ,i)); 11 int second = Integer.parseInt(s.substring(i - 2, i)); 12 if (first != 0) { 13 dp[i] += dp[i - 1]; 14 } 15 if (second >= 10 && second <= 26) { 16 dp[i] += dp[i - 2]; 17 } 18 } 19 return dp[s.length()]; 20 } 21 }
329. Longest Increasing Path in a Matrix
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Given an integer matrix, find the length of the longest increasing path. 2 3 From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed). 4 5 Example 1: 6 7 nums = [ 8 [9,9,4], 9 [6,6,8], 10 [2,1,1] 11 ] 12 Return 4 13 The longest increasing path is [1, 2, 6, 9]. 14 15 Example 2: 16 17 nums = [ 18 [3,4,5], 19 [3,2,6], 20 [2,2,1] 21 ] 22 Return 4 23 The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.
思路:这道题是我电话面试腾讯微信的一道算法题,很尴尬,当时只想到了最暴力的dfs,没有存储中间过程导致时间复杂度过高!在面试官的提示下也没有能优化!哎!还是要好好刷题啊!!!
对二维数组的每一个位置开始遍历,dfs求出以这个位置开始的最长递增长度。为了避免搜索过的位置在下一次遍历中再次重复搜索,我们定义一个二维数组cache,cache[i][j]表示当前位置开始的最长递增序列的长度,用来缓存中间结果,避免重复递归
time:O(n * m) space:O(n * m)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int longestIncreasingPath(int[][] matrix) { 3 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 4 return 0; 5 } 6 int n = matrix.length, m = matrix[0].length; 7 int max = 1; 8 for (int i = 0; i < n; i++) { 9 for (int j = 0; j < m; j++) { 10 int result = dfsHelper(matrix, i, j, new int[n][m]); 11 max = Math.max(max, result); 12 } 13 } 14 return max; 15 } 16 private int dfsHelper(int[][] matrix, int x, int y, int[][] cache) { 17 if (cache[x][y] != 0) { 18 return cache[x][y]; 19 } 20 cache[x][y] = 1; 21 int[] deltaX = new int[] {1, 0, -1, 0}; 22 int[] deltaY = new int[] {0, -1, 0, 1}; 23 for (int i = 0; i < 4; i++) { 24 int nextX = x + deltaX[i]; 25 int nextY = y + deltaY[i]; 26 if (!inBound(nextX, nextY, matrix.length, matrix[0].length)) { 27 continue; 28 } 29 if (matrix[nextX][nextY] <= matrix[x][y]) { 30 continue; 31 } 32 cache[x][y] = Math.max(cache[x][y], 1 + dfsHelper(matrix, nextX, nextY, cache)); 33 } 34 return cache[x][y]; 35 } 36 private boolean inBound(int x, int y, int n, int m) { 37 if (x < 0 || x >= n) { 38 return false; 39 } 40 if (y < 0 || y >= m) { 41 return false; 42 } 43 return true; 44 } 45 }
124. Binary Tree Maximum Path Sum
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Given a binary tree, find the maximum path sum. 2 3 For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root. 4 5 For example: 6 Given the below binary tree, 7 8 1 9 / \ 10 2 3 11 Return 6.
思路:helper表示以当前节点为最高节点的最大路径和
time:O(n) space:O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 private int max = Integer.MIN_VALUE; 12 public int maxPathSum(TreeNode root) { 13 if (root == null) { 14 return 0; 15 } 16 helper(root); 17 return max; 18 } 19 private int helper(TreeNode root) { 20 if (root == null) { 21 return 0; 22 } 23 int left = Math.max(helper(root.left), 0); 24 int right = Math.max(helper(root.right), 0); 25 max = Math.max(max, left + root.val + right); 26 return root.val + Math.max(left, right); 27 } 28 }
76. Minimum Window Substring
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). For example, S = "ADOBECODEBANC" T = "ABC" Minimum window is "BANC". Note: If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
思路:双指针。right从前往后遍历直到找到了left ~ right之间的子串包含串t,然后left++开始缩小窗口来看是否继续满足left ~ right之间的子串包含串t,知道不满足退出循环,然后right++继续判断。只要找到符合要求的子串,就更新最小长度和最小子串。
time:O(n) space:O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public String minWindow(String s, String t) { 3 if (s == null || s.length() == 0 || t == null || t.length() == 0 || s.length() < t.length()) { 4 return ""; 5 } 6 int[] target = new int[256]; 7 for (int i = 0; i < t.length(); i++) { 8 char c = t.charAt(i); 9 target[c]++; 10 } 11 int left = 0, right = 0; 12 int[] source = new int[256]; 13 int maxLength = Integer.MAX_VALUE; 14 String result = ""; 15 while (right < s.length()) { 16 char c = s.charAt(right); 17 source[c]++; 18 while (valid(source, target)) { 19 if (right - left + 1 < maxLength) { 20 maxLength = right - left + 1; 21 result = s.substring(left, right + 1); 22 } 23 source[s.charAt(left)]--; 24 left++; 25 } 26 right++; 27 } 28 return result; 29 } 30 private boolean valid(int[] source, int[] target) { 31 for (int i = 0; i < 256; i++) { 32 if (source[i] < target[i]) { 33 return false; 34 } 35 } 36 return true; 37 } 38 }
41. First Missing Positive
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given an unsorted integer array, find the first missing positive integer. For example, Given [1,2,0] return 3, and [3,4,-1,1] return 2. Your algorithm should run in O(n) time and uses constant space.
思路:索引为i的位置放i+1这个元素,然后遍历看哪个位置不符合索引i为i+1元素。
time:O(n + n),第一个n是for循环遍历n次,第二个n是最多交换n次 space:O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int firstMissingPositive(int[] nums) { 3 if (nums == null || nums.length == 0) { 4 return 1; 5 } 6 for (int i = 0; i < nums.length; i++) { 7 while (nums[i] > 0 && nums[i] <= nums.length && nums[nums[i] - 1] != nums[i]) { 8 int temp = nums[nums[i] - 1]; 9 nums[nums[i] - 1] = nums[i]; 10 nums[i] = temp; 11 } 12 } 13 for (int i = 0; i < nums.length; i++) { 14 if (nums[i] != i + 1) { 15 return i + 1; 16 } 17 } 18 return nums.length + 1; 19 } 20 }
115. Distinct Subsequences
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Given a string S and a string T, count the number of distinct subsequences of S which equals T. 2 3 A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not). 4 5 Here is an example: 6 S = "rabbbit", T = "rabbit" 7 8 Return 3.
思路:dp。
定义:dp[i][j]表示s的前i个字符含有t的前j个字符多少次。
初始化:for i:0 ~ s.length() dp[i][0] = 1
for j:1 ~ t.length() dp[0][j] = 0
状态转移方程:
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] s.charAt(i - 1) == t.charAt(j - 1)
= dp[i - 1][j] s.charAt(i - 1) != t.charAt(j - 1)
答案:dp[s.length()][t.length()]
time:O(n ^ 2) space:O(n ^ 2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int numDistinct(String s, String t) { 3 if (s == null || t == null) { 4 return 0; 5 } 6 int[][] dp = new int[s.length() + 1][t.length() + 1]; 7 for (int i = 0; i < s.length(); i++) { 8 dp[i][0] = 1; 9 } 10 for (int i = 1; i < t.length(); i++) { 11 dp[0][i] = 0; 12 } 13 for (int i = 1; i <= s.length(); i++) { 14 for (int j = 1; j <= t.length(); j++) { 15 if (s.charAt(i - 1) == t.charAt(j - 1)) { 16 dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 17 } else { 18 dp[i][j] = dp[i - 1][j]; 19 } 20 } 21 } 22 return dp[s.length()][t.length()]; 23 } 24 }
120. Triangle
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below. 2 3 For example, given the following triangle 4 [ 5 [2], 6 [3,4], 7 [6,5,7], 8 [4,1,8,3] 9 ] 10 The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). 11 12 Note: 13 Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
思路I:dp。自顶向下
time:O(n ^ 2) space:O(n ^ 2)
思路II:dp。dp[i]表示从当前层的第i个位置出发到最后一层的最小路径和。
自底向上。复制了三角形最后一行,作为用来更新的一位数组。然后逐个遍历这个DP数组,对于每个数字,和它之后的元素比较选择较小的再加上上面一行相邻位置的元素做为新的元素,然后一层一层的向上扫描,整个过程和冒泡排序的原理差不多,最后最小的元素都冒到前面,第一个元素即为所求。
time:O(n ^ 2) space:O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public int minimumTotal(List<List<Integer>> triangle) { 3 if (triangle == null || triangle.size() == 0 || triangle.get(0).size() == 0) { 4 return 0; 5 } 6 int n = triangle.size(); 7 int[] dp = new int[n]; 8 for (int i = 0; i < n; i++) { 9 dp[i] = triangle.get(n - 1).get(i); 10 } 11 for (int i = n - 2; i >= 0; i--) { 12 for (int j = 0; j <= i; j++) { 13 dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j); 14 } 15 } 16 return dp[0]; 17 } 18 }
368. Largest Divisible Subset
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0. If there are multiple solutions, return any subset is fine. Example 1: nums: [1,2,3] Result: [1,2] (of course, [1,3] will also be ok) Example 2: nums: [1,2,4,8] Result: [1,2,4,8]
思路:首先排序,方便处理,然后维护一个count[i]数组用来记录以i位置结尾的最大整除子集的长度,pre[i]用来记录满足整除的位置i前一个位置pre[i],然后维护两个变量max_count和max_index用来记录最长子集的长度和开始位置。
time:O(n^2) space:O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Solution { 2 public List<Integer> largestDivisibleSubset(int[] nums) { 3 List<Integer> result = new ArrayList<>(); 4 if (nums == null || nums.length == 0) { 5 return result; 6 } 7 Arrays.sort(nums); 8 int[] count = new int[nums.length]; 9 int[] pre = new int[nums.length]; 10 int max_count = 1, max_index = 0; 11 for (int i = 0; i < nums.length; i++) { 12 count[i] = 1; 13 pre[i] = -1; 14 for (int j = 0; j < i; j++) { 15 if (nums[i] % nums[j] == 0) { 16 if (count[j] + 1 > count[i]) { 17 count[i] = count[j] + 1; 18 pre[i] = j; 19 } 20 } 21 } 22 if (count[i] > max_count) { 23 max_count = count[i]; 24 max_index = i; 25 } 26 } 27 int index = max_index; 28 while (index != -1) { 29 result.add(nums[index]); 30 index = pre[index]; 31 } 32 Collections.reverse(result); 33 return result; 34 } 35 }
二叉树节点间的最大距离
思路:等同于求二叉树的深度,只不过在这个过程中不断更新最大节点间的距离即可。
time:O(n) space:O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package test; 2 3 public class Solution { 4 private int maxDistance = 0; 5 public int maxDistanceOfBinaryTree(TreeNode root) { 6 if (root == null) { 7 return 0; 8 } 9 int leftDepth = maxDistanceOfBinaryTree(root.left); 10 int rightDepth = maxDistanceOfBinaryTree(root.right); 11 maxDistance = Math.max(maxDistance, leftDepth + rightDepth); 12 return Math.max(leftDepth, rightDepth) + 1; 13 } 14 } 15 16 class TreeNode { 17 int val; 18 TreeNode left; 19 TreeNode right; 20 public TreeNode(int val) { 21 this.val = val; 22 } 23 }
298 Longest Consecutive Sequence
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse). Have you met this question in a real interview? Yes Example For example, 1 \ 3 / \ 2 4 \ 5 Longest consecutive sequence path is 3-4-5, so return 3. 2 \ 3 / 2 / 1 Longest consecutive sequence path is 2-3,not3-2-1, so return 2.
思路:dfs,dfs记录父节点和以父节点结尾的最长连续递增子序列的长度,定义一个全局的longest,递归到每一个节点都更新一次longest,最后的longest即为所求
time:O(n) space:O(lgn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 */ 12 13 public class Solution { 14 /** 15 * @param root: the root of binary tree 16 * @return: the length of the longest consecutive sequence path 17 */ 18 private int longest = 0; 19 public int longestConsecutive(TreeNode root) { 20 // write your code here 21 helper(root, null, 0); 22 return longest; 23 } 24 private void helper(TreeNode root, TreeNode parent, int parentLength) { 25 if (root == null) { 26 return; 27 } 28 int len = 1; 29 if (parent != null && parent.val + 1 == root.val) { 30 len += parentLength; 31 } 32 longest = Math.max(longest, len); 33 helper(root.left, root, len); 34 helper(root.right, root, len); 35 } 36 }