方法一: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 public class Codec { public String serialize (TreeNode root) { if (root == null ) return "#" ; String left = serialize(root.left); String right = serialize(root.right); return root.val + "," + left + "," + right; } public TreeNode deserialize (String data) { String[] nodes = data.split("," ); return dfs(nodes); } int i = 0 ; public TreeNode dfs (String[] nodes) { String str = nodes[i++]; if (str.equals("#" )) return null ; TreeNode root = new TreeNode (Integer.valueOf(str)); root.left = dfs(nodes); root.right = dfs(nodes); return root; } }
为什么左边的代码不行,因为如何nodes[i]是节点,i没有自增!
方法一:滑动窗口 set
用HashSet判断重复,并将左区间滑动到没有重复元素为止
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int lengthOfLongestSubstring (String s) { int length = 0 ; Set<Character> set = new HashSet <>(); for (int i = 0 , left = 0 ; i < s.length(); ++i) { char ch = s.charAt(i); if (set.contains(ch)) { while (left < i) { set.remove(s.charAt(left++)); if (!set.contains(ch)) break ; } } set.add(ch); length = Math.max(length, i - left + 1 ); } return length; } }
方法二:滑动窗口 map
用HashMap存储遍历的字符以及其下标,当出现重复字符,将left赋值为Math.max(left, map.get(ch) + 1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int lengthOfLongestSubstring (String s) { int max = 0 , left = 0 , n = s.length(); Map<Character, Integer> map = new HashMap <>(); for (int i = 0 ; i < n; ++i) { char ch = s.charAt(i); if (map.containsKey(ch)) left = Math.max(left, map.get(ch) + 1 ); map.put(ch, i); max = Math.max(max, i - left + 1 ); } return max; } }
方法一:HashMap + ListNode
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 class LRUCache { static class ListNode { int key; int val; ListNode next, pre; public ListNode (int key, int val) { this .key = key; this .val = val; } } ListNode head, tail; Map<Integer, ListNode> map; int capacity; public LRUCache (int capacity) { head = new ListNode (-1 , -1 ); tail = new ListNode (-1 , -1 ); head.next = tail; tail.pre = head; map = new HashMap <>(); this .capacity = capacity; } public int get (int key) { if (!map.containsKey(key)) return -1 ; moveToTail(key); return map.get(key).val; } public void put (int key, int value) { if (map.containsKey(key)) { moveToTail(key); map.get(key).val = value; } else { if (capacity == map.size()) delete(-1 , true ); ListNode node = new ListNode (key, value); map.put(key, node); insertIntail(key); } } public void moveToTail (int key) { delete(key, false ); insertIntail(key); } public void delete (int key, boolean isLast) { if (isLast) { ListNode toBeDelete = head.next; map.remove(toBeDelete.key); head.next = toBeDelete.next; toBeDelete.next.pre = head; } else { ListNode toBeDelete = map.get(key); toBeDelete.pre.next = toBeDelete.next; toBeDelete.next.pre = toBeDelete.pre; } } private void insertIntail (int key) { ListNode node = map.get(key); node.next = tail; tail.pre.next = node; node.pre = tail.pre; tail.pre = node; } }
方法一: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 class Solution { public TreeNode deleteNode (TreeNode root, int key) { if (root == null ) return null ; if (root.val > key) root.left = deleteNode(root.left, key); else if (root.val < key) root.right = deleteNode(root.right, key); else { if (root.left == null && root.right == null ) return null ; else if (root.left == null ) return root.right; else if (root.right == null ) return root.left; else { TreeNode cur = root.right; while (cur.left != null ) cur = cur.left; cur.left = root.left; return root.right; } } return root; } }
方法一:DP
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int maxSubArray (int [] nums) { int n = nums.length, res = nums[0 ]; int [] dp = new int [n]; dp[0 ] = nums[0 ]; for (int i = 1 ; i < n; ++i) { dp[i] = nums[i] + (dp[i - 1 ] >= 0 ? dp[i - 1 ] : 0 ); res = Math.max(res, dp[i]); } return res; } }
方法一:二分查找
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 int search (int [] nums, int target) { int n = nums.length, targetIdx = -1 ; int left = 0 , right = n - 1 ; while (left <= right) { int mid = (left + right) >> 1 ; if (nums[mid] <= nums[n - 1 ]) right = mid - 1 ; else left = mid + 1 ; } if (target > nums[n - 1 ]) targetIdx = bisearch(nums, 0 , left - 1 , target); else targetIdx = bisearch(nums, left, n - 1 , target); return targetIdx; } public int bisearch (int [] nums, int left, int right, int target) { while (left <= right) { int mid = (left + right) >> 1 ; if (nums[mid] < target) left = mid + 1 ; else if (nums[mid] == target) return mid; else right = mid - 1 ; } return -1 ; } }
题解
方法一:划分数组
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 double findMedianSortedArrays (int [] nums1, int [] nums2) { if (nums1.length > nums2.length) return findMedianSortedArrays(nums2, nums1); int m = nums1.length, n = nums2.length; int median1 = 0 , median2 = 0 ; int left = 0 , right = m; while (left <= right) { int i = (left + right) / 2 , j = (m + n + 1 ) / 2 - i; int nums_i = i == m ? Integer.MAX_VALUE : nums1[i]; int nums_im1 = i == 0 ? Integer.MIN_VALUE : nums1[i - 1 ]; int nums_j = j == n ? Integer.MAX_VALUE : nums2[j]; int nums_jm1 = j == 0 ? Integer.MIN_VALUE : nums2[j - 1 ]; if (nums_im1 <= nums_j) { median1 = Math.max(nums_im1, nums_jm1); median2 = Math.min(nums_i, nums_j); left = i + 1 ; } else { right = i - 1 ; } } return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1; } }
方法一:回溯
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 class Solution { public List<String> generateParenthesis (int n) { this .n = n; dfs(0 , n, n); return res; } private void dfs (int index, int left, int right) { if (index == 2 * n) { res.add(sb.toString()); return ; } if (left > 0 ) { sb.append('(' ); dfs(index + 1 , left - 1 , right); sb.deleteCharAt(sb.length() - 1 ); } if (right > left) { sb.append(')' ); dfs(index + 1 , left, right - 1 ); sb.deleteCharAt(sb.length() - 1 ); } } List<String> res = new LinkedList <>(); StringBuilder sb = new StringBuilder (); int n; }
方法一:前缀和 + HashMap
题解
可以用这种方法做链接中的题
map.put(0, 1)是为了让第一组满足的子数组map.containsKey(pre - k) = 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int subarraySum (int [] nums, int k) { int pre = 0 , count = 0 ; Map<Integer, Integer> map = new HashMap <>(); map.put(0 , 1 ); for (int i = 0 ; i < nums.length; ++i) { pre += nums[i]; if (map.containsKey(pre - k)) count += map.get(pre - k); map.put(pre, map.getOrDefault(pre, 0 ) + 1 ); } return count; } }
方法一:双队列
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 45 46 47 48 49 50 51 52 class Solution { public List<List<Integer>> zigzagLevelOrder (TreeNode root) { if (root == null ) return new LinkedList <>(); boolean nextRight = true ; Deque<TreeNode> queue = new LinkedList <>(), temp = new LinkedList <>(); queue.offer(root); List<List<Integer>> res = new LinkedList (); while (!queue.isEmpty()) { int size = queue.size(); List<Integer> list = new LinkedList (); for (int i = 0 ; i < size; ++i) { if (nextRight) { TreeNode cur = queue.pollFirst(); list.add(cur.val); if (cur.left != null ) temp.offerLast(cur.left); if (cur.right != null ) temp.offerLast(cur.right); } else { TreeNode cur = queue.pollLast(); list.add(cur.val); if (cur.right != null ) temp.offerFirst(cur.right); if (cur.left != null ) temp.offerFirst(cur.left); } } queue = temp; temp = new LinkedList <>(); res.add(list); nextRight = !nextRight; } return res; } }
方法一:双端队列
用栈实现不是逆序的
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 String reverseWords (String s) { Deque<String> queue = new LinkedList <>(); StringBuilder sb = new StringBuilder (); int left = 0 , right = s.length() - 1 ; while (s.charAt(left) == ' ' ) ++left; while (s.charAt(right) == ' ' ) --right; while (left <= right) { char ch = s.charAt(left++); if (ch != ' ' ) sb.append(ch); else if (ch == ' ' && sb.length() > 0 ) { queue.offerFirst(sb.toString()); sb.setLength(0 ); } } queue.offerFirst(sb.toString()); return String.join(" " , queue); } }
方法一:模拟
多debug
使用outOfBound判断最后一部分节点的数量是否少于k,如果少于k就break
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 45 46 47 48 49 50 class Solution { public ListNode reverseKGroup (ListNode head, int k) { if (k == 1 ) return head; ListNode dummyHead = new ListNode (-1 , head); ListNode pre = dummyHead, next = dummyHead, cur = head, start = dummyHead; while (cur != null && cur.next != null ) { boolean outOfBound = false ; for (int i = 0 ; i < k - 1 ; ++i) { if (cur.next == null ) { outOfBound = true ; break ; } cur = cur.next; next = cur.next; } if (outOfBound) break ; cur.next = null ; start = pre.next; pre.next = reverse(start); start.next = next; pre = start; cur = pre.next; } return dummyHead.next; } private ListNode reverse (ListNode cur) { ListNode pre = null , next; while (cur != null ) { next = cur.next; cur.next = pre;; pre = cur; cur = next; } return pre; } }
方法一:模拟
判断是否溢出
其中Integer.MAX_VALUE / 10 == res && val > 7,如果是正数val > 7溢出;如果是负数val > 8才溢出,不过等于8时,结果恰好是Integer.MIN_VALUE
[-2147483648,2147483647]
1 2 if (Integer.MAX_VALUE / 10 < res || (Integer.MAX_VALUE / 10 == res && val > 7 )) return positive ? Integer.MAX_VALUE : Integer.MIN_VALUE;
代码
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 class Solution { public int myAtoi (String s) { int left = 0 , n = s.length(); if (n == 0 ) return 0 ; while (left < n) { if (s.charAt(left) != ' ' ) break ; ++left; } if (left == n) return 0 ; boolean positive = true ; if (!isDigital(s.charAt(left))) { positive = s.charAt(left) == '-' ? false : true ; if (s.charAt(left) == '-' ) positive = false ; else if (s.charAt(left) != '+' ) return 0 ; ++left; } int res = 0 ; for (int i = left; i < n; ++i) { char ch = s.charAt(i); if (!isDigital(ch)) break ; int val = ch - '0' ; if (Integer.MAX_VALUE / 10 < res || (Integer.MAX_VALUE / 10 == res && val > 7 )) return positive ? Integer.MAX_VALUE : Integer.MIN_VALUE; res = res * 10 + val; } return positive ? res : -res; } private boolean isDigital (char ch) { return ch == '0' || ch == '1' || ch == '2' || ch == '3' || ch == '4' || ch == '5' || ch == '6' || ch == '7' || ch == '8' || ch == '9' ; } }
方法一:射气球
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 int [][] merge(int [][] intervals) { Arrays.sort(intervals, new Comparator <int []>() { @Override public int compare (int [] o1, int [] o2) { return Integer.compare(o1[0 ], o2[0 ]); } }); List<int []> list = new LinkedList <>(); int left = 0 ; for (int i = 1 ; i < intervals.length; ++i) { if (intervals[left][1 ] >= intervals[i][0 ]) intervals[left][1 ] = Math.max(intervals[left][1 ], intervals[i][1 ]); else { list.add(intervals[left]); left = i; } } intervals[left][1 ] = Math.max(intervals[left][1 ], intervals[intervals.length - 1 ][1 ]); list.add(intervals[left]); return list.toArray(new int [list.size()][]); } }
方法一:模拟
别看题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public void rotate (int [][] matrix) { int n = matrix.length; for (int i = 0 ; i < n >> 1 ; ++i) { int len = n - i * 2 ; for (int j = 0 ; j < len - 1 ; ++j) { int temp = matrix[i][i + j]; matrix[i][i + j] = matrix[n - i - j - 1 ][i]; matrix[n - i - j - 1 ][i] = matrix[n - i - 1 ][n - i - j - 1 ]; matrix[n - i - 1 ][n - i - j - 1 ] = matrix[i + j][n - i - 1 ]; matrix[i + j][n - i - 1 ] = temp; } } } }
方法一:排序 + 双指针
题解
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 List<List<Integer>> threeSum (int [] nums) { int n = nums.length; List<List<Integer>> res = new LinkedList <>(); Arrays.sort(nums); for (int i = 0 ; i < n; ++i) { if (nums[i] > 0 ) return res; if (i > 0 && nums[i] == nums[i - 1 ]) continue ; int left = i + 1 , right = n - 1 ; while (left < right) { if (nums[i] + nums[left] + nums[right] == 0 ) { res.add(Arrays.asList(nums[i], nums[left], nums[right])); while (left < right && nums[left] == nums[left + 1 ]) ++left; while (left < right && nums[right] == nums[right - 1 ]) --right; ++left; --right; } else if (nums[i] + nums[left] + nums[right] < 0 ) ++left; else --right; } } return res; } }
方法一:HashMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public int [] twoSum(int [] nums, int target) { int n = nums.length; HashMap<Integer, Integer> map = new HashMap <>(); int [] res = new int [2 ]; for (int i = 0 ; i < n; ++i) { if (map.containsKey(target - nums[i])) { res[0 ] = i; res[1 ] = map.get(target - nums[i]); } map.put(nums[i], i); } return res; } }
方法一:DP
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 class Solution { public String longestPalindrome (String s) { int n = s.length(), max = 0 ; int [] maxIndex = new int [2 ]; int [][] dp = new int [n][n]; for (int i = 0 ; i < n; ++i) { for (int j = i; j >= 0 ; --j) { if (i - j + 1 == 1 ) dp[i][j] = 1 ; else if (i - j + 1 == 2 ) dp[i][j] = s.charAt(i) == s.charAt(j) ? 2 : 0 ; else if (i - j + 1 == 3 ) dp[i][j] = s.charAt(i) == s.charAt(j) ? 3 : 0 ; else { if (s.charAt(i) != s.charAt(j)) dp[i][j] = 0 ; else dp[i][j] = dp[i - 1 ][j + 1 ] > 0 ? dp[i - 1 ][j + 1 ] + 2 : 0 ; } if (dp[i][j] > max) { max = dp[i][j]; maxIndex = new int []{j, i}; } } } return s.substring(maxIndex[0 ], maxIndex[1 ] + 1 ); } }