Path Sum 3
使用前缀和,每次把一个路径看成一个数组,计算前缀和,两个点的差值为sum时即找到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public int pathSum (TreeNode root, int sum) { Map<Integer, Integer> map = new HashMap<>(); map.put(0 , 1 ); return backtrack(root, 0 , sum, map); } public int backtrack (TreeNode root, int sum, int target, Map<Integer, Integer> map) { if (root == null ) return 0 ; sum += root.val; int res = map.getOrDefault(sum - target, 0 ); map.put(sum, map.getOrDefault(sum, 0 )+1 ); res += backtrack(root.left, sum, target, map) + backtrack(root.right, sum, target, map); map.put(sum, map.get(sum)-1 ); return res; }
最后一定要注意有一个将map中sum对应值减一的操作
Binary Tree Maximum Path Sum 找到二叉树里面具有最大和(max sum)的路径,这个路径不一定要从上到下,就是二叉树中随便一条路径,但是不能有分叉,也就是说路径是一条,不会分开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { int max = Integer.MIN_VALUE; public int maxPathSum (TreeNode root) { helper(root); return max; } public int helper (TreeNode root) { if (root == null ) return 0 ; int left = Math.max(0 , helper(root.left)); int right = Math.max(0 , helper(root.right)); max = Math.max(max, root.val + left + right); return root.val+Math.max(left,right); } }
Sum Root to Leaf Numbers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { int res = 0 ; public int sumNumbers (TreeNode root) { helper(root, 0 ); return res; } public void helper (TreeNode root, int temp) { if (root == null ) { return ; } if (root.left == null && root.right == null ) { temp = temp * 10 + root.val; res += temp; } helper(root.left, temp * 10 + root.val); helper(root.right, temp * 10 + root.val); } }
Compares two strings lexicographically字典序比较两String 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int compareTo (String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; int lim = Math.min(len1, len2); char v1[] = value; char v2[] = anotherString.value; int k = 0 ; while (k < lim) { char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } return len1 - len2; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution { String ans = "~" ; public String smallestFromLeaf (TreeNode root) { dfs(root, new StringBuilder()); return ans; } public void dfs (TreeNode root, StringBuilder sb) { if (root == null ) return ; if (root.left == null && root.right == null ) { sb.insert(0 , (char )('a' + root.val)); String s = sb.toString(); if (s.compareTo(ans) < 0 ) ans = s; sb.deleteCharAt(0 ); } sb.insert(0 , (char )('a' + root.val)); dfs(root.left, sb); dfs(root.right, sb); sb.deleteCharAt(0 ); } }
使用String和StringBuilder的区别 “StringBuilder” is a mutable object, it will hold its value after returning.Whereas String creates a copy in every recursion, you don’t need to worry about the “side-effect” when backtrack.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Solution { public List<String> binaryTreePaths (TreeNode root) { List<String> res = new ArrayList<>(); helper(res, new StringBuilder(), root); return res; } public void dfs (List<String> res, String temp, TreeNode root) { if (root == null ) return ; if (root.left == null && root.right == null ) { res.add(temp + root.val); } dfs(res, temp+root.val+"->" , root.left); dfs(res, temp+root.val+"->" , root.right); } public void helper (List<String> res, StringBuilder temp, TreeNode root) { if (root == null ) return ; int len = temp.length(); temp.append(root.val); if (root.left == null && root.right == null ) { res.add(temp.toString()); } temp.append("->" ); helper(res, temp, root.left); helper(res, temp, root.right); temp.setLength(len); } }
Delete Node in a BST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public TreeNode deleteNode (TreeNode root, int key) { if (root == null ){ return null ; } if (key < root.val){ root.left = deleteNode(root.left, key); }else if (key > root.val){ root.right = deleteNode(root.right, key); }else { if (root.left == null ){ return root.right; }else if (root.right == null ){ return root.left; } TreeNode minNode = findMin(root.right); root.val = minNode.val; root.right = deleteNode(root.right, root.val); } return root; } private TreeNode findMin (TreeNode node) { while (node.left != null ){ node = node.left; } return node; } }
使用map先保存新创建的node,再连接节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Solution { public Node copyRandomList (Node head) { if (head == null ) return null ; Map<Node, Node> map = new HashMap<>(); Node node = head; while (node != null ) { map.put(node, new Node(node.val)); node = node.next; } node = head; while (node != null ) { map.get(node).next = map.get(node.next); map.get(node).random = map.get(node.random); node = node.next; } return map.get(head); } }
法二,不使用map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public Node copyRandomList (Node head) { if (head == null ) return null ; Node node = head; while (node != null ) { Node next = node.next; node.next = new Node(node.val); node.next.next = next; node = next; } node = head; while (node != null ) { if (node.random != null ) { node.next.random = node.random.next; } node = node.next.next; } node = head; Node copyHead = head.next; Node copy = copyHead; while (copy.next != null ) { node.next = node.next.next; node = node.next; copy.next = copy.next.next; copy = copy.next; } node.next =node.next.next; return copyHead; } }
dfs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { private Map<Node, Node> map = new HashMap<>(); public Node cloneGraph (Node node) { return dfsClone(node); } Node dfsClone (Node node) { if (node == null ) return null ; if (map.containsKey(node)) return map.get(node); Node newNode = new Node(node.val); map.put(node, newNode); for (Node neighbor: node.neighbors) { newNode.neighbors.add(dfsClone(neighbor)); } return newNode; } }
bfs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public Node cloneGraph (Node node) { if (node == null ) return null ; Queue<Node> queue = new LinkedList<>(); queue.add(node); Map<Node, Node> map = new HashMap<>(); map.put(node, new Node(node.val)); while (!queue.isEmpty()) { Node curr = queue.poll(); for (Node neighbor: curr.neighbors) { if (!map.containsKey(neighbor)) { map.put(neighbor, new Node(neighbor.val)); queue.add(neighbor); } map.get(curr).neighbors.add(map.get(neighbor)); } } return map.get(node); } }
在给定的数列中有多少等比数列(最少3个一组,并且是连续的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int numberOfArithmeticSlices (int [] A) { int res = 0 ; if (A.length < 3 ) return res; for (int s = 0 ; s < A.length - 2 ; s++) { int dist = A[s + 1 ] - A[s]; for (int e = s + 2 ; e < A.length; e++) { int i = 0 ; for (i = s + 1 ; i <= e; i++) { if (A[i] - A[i - 1 ] != dist) break ; } if (i > e) res++; } } return res; } }
事实上,如果当前这个序列经过判断不是等差数列的话,后面就可以不用判断了。如果当前序列经过判断是等差数列,那么下一个(也就是结尾往后移一位的序列,只需判断新增的那个是否构成等差即可。
dp解法的话,比较偏数学1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public int numberOfArithmeticSlices (int [] A) { int [] dp = new int [A.length]; int res = 0 ; for (int i = 2 ; i < dp.length; i++) { if (A[i] - A[i - 1 ] == A[i - 1 ] - A[i -2 ]) { dp[i] = dp[i - 1 ] + 1 ; res += dp[i]; } } return res; } }
使用hashmap来存储状态
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int longestSubsequence (int [] arr, int difference) { int maxLen = 0 ; Map<Integer, Integer> dp = new HashMap<>(); for (int i = 0 ; i < arr.length; i++) { int len = dp.getOrDefault(arr[i] - difference, 0 ) + 1 ; dp.put(arr[i], len); maxLen = Math.max(maxLen, len); } return maxLen; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public ListNode reverseKGroup (ListNode head, int k) { int count = 0 ; ListNode node = head; while (count < k) { if (node == null ) return head; count++; node = node.next; } ListNode pre = reverseKGroup(node, k); while (count > 0 ) { ListNode next = head.next; head.next = pre; pre = head; head = next; count--; } return pre; } }
在BST中搜索最低公共祖先。因为是二叉树结构,所以p和q分布在公共祖先的左右两边,而且只存在一个节点满足这个条件。最低祖先上边的节点也是祖先,但是pq是分布在它们的一边(BST)
1 2 3 4 5 6 7 8 9 10 class Solution { public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) { if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q); else if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q); else return root; } }
这里不是BST,只是普通的二叉树。 依然是找是不是在左右子树中有p或q。1 2 3 4 5 6 7 8 9 10 11 class Solution { public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) return root; TreeNode fromLeft = lowestCommonAncestor(root.left, p, q); TreeNode fromRight = lowestCommonAncestor(root.right, p, q); if (fromLeft != null && fromRight != null ) return root; return fromLeft != null ? fromLeft : fromRight; } }