年度回顾 力扣 Rewind’23 - 年度回顾 (leetcode.cn)
数组 一维 除自身以外数组的乘积 238. 除自身以外数组的乘积 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int [] productExceptSelf(int [] nums) { int len = nums.length; int [] ans = new int [len]; int [] L = new int [len]; int [] R = new int [len]; L[0 ] = 1 ; for (int i = 1 ; i < len; i++) { L[i] = L[i - 1 ] * nums[i - 1 ]; } R[len - 1 ] = 1 ; for (int i = len - 2 ; i >= 0 ; i--) { R[i] = R[i + 1 ] * nums[i + 1 ]; } for (int i = 0 ; i < len; i++) { ans[i] = L[i] * R[i]; } return ans; }
下一个排列 31. 下一个排列 - 力扣(LeetCode)
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 public void nextPermutation (int [] nums) { int i = nums.length - 2 ; while (i >= 0 && nums[i] >= nums[i + 1 ]){ i--; } if (i >= 0 ){ int j = nums.length - 1 ; while (j >= 0 && nums[i] >= nums[j]){ j--; } swap(nums, i, j); } reverse(nums, i + 1 ); } public void swap (int [] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } public void reverse (int [] nums, int start) { int left = start, right = nums.length - 1 ; while (left < right) { swap(nums, left, right); left++; right--; } }
按规则计算统计结果 LCR 191. 按规则计算统计结果 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int [] statisticalResult(int [] arrayA) { if (arrayA.length == 0 ) return arrayA; int len = arrayA.length; int [] L = new int [len]; int [] R = new int [len]; L[0 ] = 1 ; for (int i = 1 ; i < len; i++) { L[i] = L[i - 1 ] * arrayA[i - 1 ]; } R[len - 1 ] = 1 ; for (int i = len - 2 ; i >= 0 ; i--) { R[i] = R[i + 1 ] * arrayA[i + 1 ]; } int [] ans = new int [len]; for (int i = 0 ; i < len; i++) { ans[i] = L[i] * R[i]; } return ans; }
数组中重复的数据 442. 数组中重复的数据 - 力扣(LeetCode)
下标交换法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public List<Integer> findDuplicates (int [] nums) { for (int i = 0 ; i < nums.length; i++) { while (nums[i] != nums[nums[i] - 1 ]) { swap(nums, i, nums[i] - 1 ); } } List<Integer> res = new ArrayList <>(); for (int i = 0 ; i < nums.length; i++) { if (i != nums[i] - 1 ) { res.add(nums[i]); } } return res; } public void swap (int [] nums, int index1, int index2) { int temp = nums[index1]; nums[index1] = nums[index2]; nums[index2] = temp; }
负号标记法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public List<Integer> findDuplicates (int [] nums) { List<Integer> res = new ArrayList <>(); for (int i = 0 ; i < nums.length; i++) { int x = Math.abs(nums[i]); if (nums[x - 1 ] > 0 ) { nums[x - 1 ] = -nums[x - 1 ]; } else { res.add(x); } } return res; }
缺失的第一个正数 41. 缺失的第一个正数 - 力扣(LeetCode)
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 public int firstMissingPositive (int [] nums) { int n = nums.length; for (int i = 0 ; i < n; i++) { if (nums[i] <= 0 ) nums[i] = n + 1 ; } for (int i = 0 ; i < n; i++) { int num = Math.abs(nums[i]); int index = num - 1 ; if (index < n){ nums[index] = -Math.abs(nums[index]); } } for (int i = 0 ; i < n; i++) { if (nums[i] > 0 ) return i + 1 ; } return n + 1 ; }
在排序数组中查找元素的第一个和最后一个位置 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
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 public int [] searchRange(int [] nums, int target) { int left = lowerBound(nums, target); if (left >= nums.length || nums[left] != target) { return new int []{-1 , -1 }; } int right = lowerBound(nums, target + 1 ) - 1 ; return new int []{left, right}; } private int lowerBound (int [] nums, int target) { int left = 0 , right = nums.length - 1 ; while (left <= right) { int mid = (left + right) / 2 ; if (nums[mid] >= target) { right = mid - 1 ; } else { left = mid + 1 ; } } return left; } private int lowerBound (int [] nums, int target) { int left = 0 , right = nums.length; while (left < right) { int mid = (left + right) / 2 ; if (nums[mid] >= target) { right = mid; } else { left = mid + 1 ; } } return left; }
二维 旋转图像 48. 旋转图像 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void rotate (int [][] matrix) { int n = matrix.length; int count = 0 ; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < count; j++) { swap(matrix, i, j, j, i); } count++; } for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n / 2 ; j++) { swap(matrix, i, j, i, n - 1 - j); } } } private void swap (int [][] matrix, int a1, int b1, int a2, int b2) { int temp = matrix[a1][b1]; matrix[a1][b1] = matrix[a2][b2]; matrix[a2][b2] = temp; }
矩阵置零 73. 矩阵置零 - 力扣(LeetCode)
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 public void setZeroes (int [][] matrix) { int m = matrix.length; int n = matrix[0 ].length; boolean flagRow0 = false ; boolean flagCol0 = false ; for (int i = 0 ; i < m; i++) { if (matrix[i][0 ] == 0 ) { flagCol0 = true ; break ; } } for (int j = 0 ; j < n; j++) { if (matrix[0 ][j] == 0 ) { flagRow0 = true ; break ; } } for (int i = 1 ; i < m; i++) { for (int j = 1 ; j < n; j++) { if (matrix[i][j] == 0 ){ matrix[0 ][j] = matrix[i][0 ] = 0 ; } } } for (int i = 1 ; i < m; i++) { for (int j = 1 ; j < n; j++) { if (matrix[0 ][j] == 0 || matrix[i][0 ] == 0 ){ matrix[i][j] = 0 ; } } } if (flagCol0) { for (int i = 0 ; i < m; i++) { matrix[i][0 ] = 0 ; } } if (flagRow0) { for (int j = 0 ; j < n; j++) { matrix[0 ][j] = 0 ; } } }
螺旋矩阵 54. 螺旋矩阵 - 力扣(LeetCode)
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 public List<Integer> spiralOrder (int [][] matrix) { List<Integer> res = new LinkedList <>(); int m = matrix.length, n = matrix[0 ].length; int left = 0 , right = n - 1 ; int top = 0 , bottom = m - 1 ; int count = m * n; while (count > 0 ) { for (int j = left; j <= right && count > 0 ; j++) { res.add(matrix[top][j]); count--; } top++; for (int i = top; i <= bottom && count > 0 ; i++) { res.add(matrix[i][right]); count--; } right--; for (int j = right; j >= left && count > 0 ; j--) { res.add(matrix[bottom][j]); count--; } bottom--; for (int i = bottom; i >= top && count > 0 ; i--) { res.add(matrix[i][left]); count--; } left++; } return res; }
搜索二维矩阵 II 240. 搜索二维矩阵 II - 力扣(LeetCode)
z字法 :对某个节点来说,上边是小的,右边是大的,组成一个you’xu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public boolean searchMatrix (int [][] matrix, int target) { int row = matrix.length - 1 ; int col = 0 ; while (row >= 0 && col < matrix[0 ].length) { if (matrix[row][col] == target) { return true ; } if (matrix[row][col] > target) { row--; }else { col++; } } return false ; }
合并区间 56. 合并区间 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int [][] merge(int [][] intervals) { Arrays.sort(intervals, (v1, v2) -> v1[0 ] - v2[0 ]); int [][] ans = new int [intervals.length][2 ]; ans[0 ] = intervals[0 ]; int index = 0 ; for (int i = 1 ; i < intervals.length; i++) { if (ans[index][1 ] >= intervals[i][0 ]) { ans[index][1 ] = Math.max(ans[index][1 ], intervals[i][1 ]); } else { ans[++index] = intervals[i]; } } return Arrays.copyOf(ans, index + 1 ); }
字符串 字符串相加 415. 字符串相加 - 力扣(LeetCode)
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 public String addStrings (String num1, String num2) { char [] s1 = num1.toCharArray(); char [] s2 = num2.toCharArray(); int p1 = s1.length - 1 , p2 = s2.length - 1 ; int flag = 0 ; StringBuilder ans = new StringBuilder (); while (p1 >= 0 || p2 >= 0 ) { int num = 0 ; if (p1 < 0 ) { num = s2[p2--] - '0' + flag; } else if (p2 < 0 ) { num = s1[p1--] - '0' + flag; } else { num = s2[p2--] - '0' + s1[p1--] - '0' + flag; } if (num >= 10 ) { flag = 1 ; num %= 10 ; } else flag = 0 ; ans.append(num); } if (flag == 1 ) { ans.append(1 ); } return ans.reverse().toString(); }
替换空格 请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
找不到原题了
LCR 122. 路径加密 - 力扣(LeetCode)
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 public String replaceSpace (String s) { int cnt = 0 ; for (int i = 0 ; i < s.length(); i++){ char c = s.charAt(i); if (c == ' ' ){ cnt++; } } char [] res = new char [s.length() + 2 * cnt]; int index = 0 ; for (int i = 0 ; i < s.length(); i++){ char c = s.charAt(i); if (c != ' ' ){ res[index++] = c; }else { res[index++] = '%' ; res[index++] = '2' ; res[index++] = '0' ; } } return new String (res); }
反转字符串中的单词 151. 反转字符串中的单词 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 public String reverseWords (String s) { String[] words = s.split(" " ); StringBuilder sb = new StringBuilder (); for (int i = words.length - 1 ; i >= 0 ; i--) { String word = words[i]; if (!word.isEmpty()) { sb.append(word).append(" " ); } } sb.deleteCharAt(sb.length() - 1 ); return sb.toString(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public String reverseWords (String s) { int left = s.length() - 1 , right = s.length(); StringBuilder sb = new StringBuilder (); while (left >= 0 ) { while (left >= 0 && s.charAt(left) != ' ' ) left--; sb.append(s.substring(left + 1 , right)).append(" " ); while (left >= 0 && s.charAt(left) == ' ' ) left--; right = left + 1 ; } return sb.toString().trim(); }
最长回文子串 5. 最长回文子串 - 力扣(LeetCode)
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 public String longestPalindrome (String s) { if (s.isEmpty()) { return "" ; } int start = 0 , end = 0 ; for (int i = 0 ; i < s.length(); i++) { int len1 = expandAroundCenter(s, i, i); int len2 = expandAroundCenter(s, i, i + 1 ); int len = Math.max(len1, len2); if (len > end - start + 1 ) { start = i - (len - 1 ) / 2 ; end = i + len / 2 ; } } return s.substring(start, end + 1 ); } public int expandAroundCenter (String s, int left, int right) { while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) { left--; right++; } return right - left - 1 ; }
哈希表 分类 数组、set、map
是否出现相同元素、同类元素、有某种关系的元素(如相加为x)
两数之和 1. 两数之和 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 public int [] twoSum(int [] nums, int target) { Map<Integer, Integer> map = new HashMap <>(); for (int i = 0 ; i < nums.length; i++) { int x = target - nums[i]; if (map.containsKey(x)) { return new int []{map.get(x), i}; } else { map.put(nums[i], i); } } return new int []{-1 , -1 }; }
和为 K 的子数组(和两数之和相似) 当前节点还要一次遍历,考虑用哈希表
560. 和为 K 的子数组 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public int subarraySum (int [] nums, int k) { Map<Integer, Integer> map = new HashMap <>(); map.put(0 , 1 ); int preNum = 0 ; int ans = 0 ; for (int num : nums) { preNum += num; int x = preNum - k; if (map.containsKey(x)) { ans += map.get(x); } map.put(preNum, map.getOrDefault(preNum, 0 ) + 1 ); } return ans; }
路径总和 III 437. 路径总和 III - 力扣(LeetCode)
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 public int pathSum (TreeNode root, int targetSum) { Map<Long, Integer> prefix = new HashMap <Long, Integer>(); prefix.put(0L , 1 ); return dfs(root, prefix, 0 , targetSum); } public int dfs (TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) { if (root == null ) { return 0 ; } int ret = 0 ; curr += root.val; ret = prefix.getOrDefault(curr - targetSum, 0 ); prefix.put(curr, prefix.getOrDefault(curr, 0 ) + 1 ); ret += dfs(root.left, prefix, curr, targetSum); ret += dfs(root.right, prefix, curr, targetSum); prefix.put(curr, prefix.getOrDefault(curr, 0 ) - 1 ); return ret; }
字母异位词分组 49. 字母异位词分组 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public List<List<String>> groupAnagrams (String[] strs) { final HashMap<String, List<String>> map = new HashMap <>(); for (String str : strs) { final char [] array = str.toCharArray(); String oldArray = new String (array); Arrays.sort(array); List<String> strings = map.get(new String (array)); if (strings == null ) { strings = new ArrayList <>(); } strings.add(oldArray); map.put(new String (array), strings); } final List<List<String>> res = new ArrayList <>(); map.forEach((key, value) -> { res.add(map.get(key)); }); return res; }
最长连续序列 128. 最长连续序列 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public int longestConsecutive (int [] nums) { final HashSet<Integer> set = new HashSet <>(); for (int num : nums) { set.add(num); } int longestStreak = 0 ; for (int num : nums) { int currentNum = num; if (!set.contains(num - 1 )) { int currentStreak = 1 ; while (set.contains(currentNum + 1 )) { currentNum += 1 ; currentStreak += 1 ; } longestStreak = Math.max(longestStreak, currentStreak); } } return longestStreak; }
字符串中的第一个唯一字符 387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 public int firstUniqChar (String s) { char [] dictionary = new char [26 ]; char [] chars = s.toCharArray(); for (char c : chars) { dictionary[c - 'a' ]++; } for (int i = 0 ; i < chars.length; i++) { if (dictionary[chars[i] - 'a' ] == 1 ) return i; } return -1 ; }
栈、队列 单调栈有感,一个是接雨水维护单调递减的栈,一个是计算矩形最大面积维护单调递增的栈,两者都可以从某个柱子往左往右找到更大或者更小的值,这样就会形成凹槽或者突起,那么单调栈可以降低时间复杂度到O(n),用空间换取时间,每次元素的出栈,都意味着这个元素的右边是第一个更大/更小的元素,弹出后的栈顶元素是左边是第一个更大/更小的元素,这样就可以计算了。
用栈实现队列 232. 用栈实现队列 - 力扣(LeetCode)
用s1作为主栈,s2为辅助栈
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 class MyQueue { Stack<Integer> S1, S2; public MyQueue () { S1 = new Stack (); S2 = new Stack (); } public void push (int x) { S1.push(x); } public int pop () { while (!S1.isEmpty()){ S2.push(S1.pop()); } int res = S2.pop(); while (!S2.isEmpty()){ S1.push(S2.pop()); } return res; } public int peek () { while (!S1.isEmpty()){ S2.push(S1.pop()); } int res = S2.peek(); while (!S2.isEmpty()){ S1.push(S2.pop()); } return res; } public boolean empty () { return S1.isEmpty(); } }
有效的括号 20. 有效的括号 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public boolean isValid (String s) { char [] chars = s.toCharArray(); Stack<Character> S = new Stack <>(); HashMap<Character, Character> map = new HashMap <>(3 ); map.put('(' , ')' ); map.put('[' , ']' ); map.put('{' , '}' ); for (char c : chars) { if (c == '(' || c == '[' || c == '{' ) { S.push(c); } else { if (S.isEmpty()){ return false ; }else { Character popC = S.pop(); if (!map.get(popC).equals(c)) return false ; } } } return S.isEmpty(); }
接雨水 42. 接雨水 - 力扣(LeetCode)
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 public int trap (int [] height) { Stack<Integer> S = new Stack (); S.push(0 ); int sum = 0 ; for (int i = 1 ; i < height.length; i++) { Integer top = S.peek(); if (height[i] < height[top]) { S.push(i); } else if (height[i] == height[top]) { S.pop(); S.push(i); } else { while (!S.isEmpty() && height[i] > height[S.peek()]){ int mid = S.pop(); if (!S.isEmpty()){ int left = S.peek(); int width = i - left - 1 ; int high = Math.min(height[i], height[left]) - height[mid]; sum += width * high; } } S.push(i); } } return sum; }
最小栈 155. 最小栈 - 力扣(LeetCode)
辅助栈
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 class MinStack { Deque<Integer> xStack; Deque<Integer> minStack; public MinStack () { xStack = new LinkedList <Integer>(); minStack = new LinkedList <Integer>(); minStack.push(Integer.MAX_VALUE); } public void push (int val) { xStack.push(val); minStack.push(Math.min(minStack.peek(), val)); } public void pop () { xStack.pop(); minStack.pop(); } public int top () { return xStack.peek(); } public int getMin () { return minStack.peek(); } }
辅助数字代替辅助栈
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 MinStack { Deque<Integer> xStack; int min = Integer.MAX_VALUE; public MinStack () { xStack = new LinkedList <Integer>(); } public void push (int val) { if (val <= min){ xStack.push(min); min = val; } xStack.push(val); } public void pop () { int val = xStack.pop(); if (val == min){ min = xStack.pop(); } } public int top () { return xStack.peek(); } public int getMin () { return min; } }
验证栈序列 946. 验证栈序列 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public boolean validateStackSequences (int [] pushed, int [] popped) { Stack<Integer> S = new Stack <>(); int length = pushed.length; int j = 0 ; for (int i = 0 ; i < length; i++) { S.push(pushed[i]); while (!S.isEmpty() && S.peek() == popped[j]){ S.pop(); j++; } } return S.isEmpty(); }
链表 1、删除 删除有删一个、或者是一段区间:
一个的话用prev节点下一个对比val找就行
一段区间需要一个基准值slow指针,一个fast指针对比slow找区间,最后的区间是[slow, fast),区间可能有1个节点或者多个节点
2、反转链表 找到要反转的区间[startNode, endNode],用prev和nex记录区间子链表的前驱后继节点,用于反转后再加入链表
反转一般用三指针,while条件一般是cur != null 或者是 prev != endNode
3、合并有序链表 两个或者多个有序链表的合并,双指针判断递归处理,多个考虑归并处理(用递归拆解成小问题,即每次只合并两个链表)
重排链表 143. 重排链表 - 力扣(LeetCode)
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 public void reorderList (ListNode head) { if (head == null ) { return ; } ListNode slow = head, fast = head; while (fast.next != null && fast.next.next != null ) { slow = slow.next; fast = fast.next.next; } ListNode mid = slow; ListNode l1 = head; ListNode l2 = mid.next; mid.next = null ; l2 = reverseList(l2); mergeList(l1, l2); } private void mergeList (ListNode l1, ListNode l2) { ListNode p1, p2; while (l1 != null && l2 != null ) { p1 = l1.next; p2 = l2.next; l1.next = l2; l2.next = p1; l2 = p2; l1 = p1; } } private ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode cur = head; while (cur != null ) { ListNode nex = cur.next; cur.next = prev; prev = cur; cur = nex; } return prev; }
相交链表 160. 相交链表 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 public ListNode getIntersectionNode (ListNode headA, ListNode headB) { if (headA == null || headB == null ) return null ; ListNode pA = headA, pB = headB; while (pA != pB) { pA = pA == null ? pB : pA.next; pB = pB == null ? pA : pB.next; } return pA; }
环形链表 141. 环形链表 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 public boolean hasCycle (ListNode head) { if (head == null ) return false ; ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null ) { slow = slow.next; fast = fast.next.next; if (slow == fast) return true ; } return false ; }
环形链表 II 142. 环形链表 II - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public ListNode detectCycle (ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null ) { slow = slow.next; fast = fast.next.next; if (slow == fast) { ListNode p1 = head; ListNode p2 = slow; while (p1 != p2) { p1 = p1.next; p2 = p2.next; } return p1; } } return null ; }
移除链表元素 203. 移除链表元素 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public ListNode removeElements (ListNode head, int val) { ListNode hair = new ListNode (-1 ); hair.next = head; ListNode cur = hair; while (cur != null && cur.next != null ) { if (cur.next.val == val) { cur.next = cur.next.next; }else { cur = cur.next; } } return hair.next; }
删除链表中的节点(特殊) 237. 删除链表中的节点 - 力扣(LeetCode)
1 2 3 4 5 6 public void deleteNode (ListNode node) { node.val = node.next.val; node.next = node.next.next; }
删除排序链表中的重复元素 83. 删除排序链表中的重复元素 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; ListNode slow = head, fast = head.next; while (fast != null ) { if (slow.val == fast.val) { slow.next = fast.next; } else { slow = slow.next; } fast = fast.next; } return head; }
删除排序链表中的重复元素 II 82. 删除排序链表中的重复元素 II - 力扣(LeetCode)
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 public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; ListNode hair = new ListNode (-1 ); hair.next = head; ListNode prev = hair; ListNode slow = head, fast = head.next; while (fast != null ) { boolean isDelete = false ; while (fast != null && slow.val == fast.val) { fast = fast.next; isDelete = true ; } if (isDelete) { prev.next = fast; } else { prev = slow; } slow = fast; if (fast != null ) fast = fast.next; } return hair.next; }
反转链表 206. 反转链表 - 力扣(LeetCode)
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public ListNode reverseList (ListNode head) { ListNode prev = null ; ListNode cur = head; ListNode nex = null ; while (cur != null ) { nex = cur.next; cur.next = prev; prev = cur; cur = nex; } return prev; }
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 public ListNode reverseList (ListNode head) { return reverseList(null , head); } public ListNode reverseList (ListNode p1, ListNode p2) { if (p2 == null ) return p1; ListNode nex = p2.next; p2.next = p1; return reverseList(p2, nex); }
反转链表 II 92. 反转链表 II - 力扣(LeetCode)
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 public ListNode reverseBetween (ListNode head, int left, int right) { ListNode hair = new ListNode (-1 ); hair.next = head; ListNode prev = hair, nex = null ; ListNode p = hair; int count = 0 ; while (count < left) { prev = p; p = p.next; count++; } ListNode start = p; while (count < right) { p = p.next; count++; } ListNode end = p; nex = end.next; prev.next = null ; reverse(start, end); prev.next = end; start.next = nex; return hair.next; } public void reverse (ListNode leftNode, ListNode rightNode) { ListNode pre = null ; ListNode cur = leftNode; ListNode nex; while (pre != rightNode) { nex = cur.next; cur.next = pre; pre = cur; cur = nex; } }
K 个一组翻转链表 25. K 个一组翻转链表 - 力扣(LeetCode)
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 public ListNode reverseKGroup (ListNode head, int k) { ListNode hair = new ListNode (-1 ); hair.next = head; ListNode cur = head; ListNode prev = hair, nex; while (cur != null ) { ListNode start = cur, end; int count = 0 ; while (count < k - 1 && cur != null ) { cur = cur.next; count++; } end = cur; if (end == null ){ return hair.next; } prev.next = null ; nex = cur != null ? cur.next : null ; reverseList(start, end); prev.next = end; start.next = nex; cur = start.next; prev = start; } return hair.next; } public void reverseList (ListNode head, ListNode tail) { ListNode left = head; ListNode cur = left; ListNode prev = null , nex; while (prev != tail) { nex = cur.next; cur.next = prev; prev = cur; cur = nex; } }
随机链表的复制 138. 随机链表的复制 - 力扣(LeetCode)
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 public Node copyRandomList (Node head) { if (head == null ) return null ; Node cur = head; while (cur != null ) { Node nex = cur.next; Node newNode = new Node (cur.val); cur.next = newNode; newNode.next = nex; cur = nex; } cur = head; while (cur != null ) { if (cur.random != null ) cur.next.random = cur.random.next; cur = cur.next.next; } Node hair = new Node (-1 ); Node p = hair; cur = head; while (cur != null ) { p.next = cur.next; p = cur.next; cur.next = p.next; cur = cur.next; } return hair.next; }
Hash表法
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 public Node copyRandomList (Node head) { if (head==null ) { return null ; } Map<Node,Node> map = new HashMap <Node,Node>(); Node p = head; while (p!=null ) { Node newNode = new Node (p.val); map.put(p,newNode); p = p.next; } p = head; while (p!=null ) { Node newNode = map.get(p); if (p.next!=null ) { newNode.next = map.get(p.next); } if (p.random!=null ) { newNode.random = map.get(p.random); } p = p.next; } return map.get(head); }
合并两个有序链表 21. 合并两个有序链表 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 public ListNode mergeTwoLists (ListNode list1, ListNode list2) { if (list2 == null ) return list1; if (list1 == null ) return list2; if (list1.val < list2.val) { list1.next = mergeTwoLists(list1.next, list2); return list1; } else { list2.next = mergeTwoLists(list1, list2.next); return list2; } }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public ListNode mergeTwoLists (ListNode list1, ListNode list2) { ListNode hair = new ListNode (-1 ); ListNode cur = hair; while (list1 != null && list2 != null ) { if (list1.val < list2.val) { cur.next = new ListNode (list1.val); list1 = list1.next; } else { cur.next = new ListNode (list2.val); list2 = list2.next; } cur = cur.next; } if (list1 != null ) cur.next = list1; if (list2 != null ) cur.next = list2; return hair.next; }
合并 K 个升序链表 23. 合并 K 个升序链表 - 力扣(LeetCode)
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 public ListNode mergeKLists (ListNode[] lists) { return merge(lists, 0 , lists.length - 1 ); } private ListNode merge (ListNode[] lists, int l, int r) { if (l > r) return null ; if (l == r) return lists[l]; int mid = (l + r) / 2 ; ListNode leftMerge = merge(lists, l, mid); ListNode rightMerge = merge(lists, mid + 1 , r); return mergeTwoList(leftMerge, rightMerge); } private ListNode mergeTwoList (ListNode l1, ListNode l2) { if (l1 == null ) return l2; if (l2 == null ) return l1; if (l1.val < l2.val) { l1.next = mergeTwoList(l1.next, l2); return l1; } else { l2.next = mergeTwoList(l1, l2.next); return l2; } }
排序链表 148. 排序链表 - 力扣(LeetCode)
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 public ListNode sortList (ListNode head) { if (head == null ) return null ; int length = 0 ; ListNode p = head; while (p != null ) { p = p.next; length++; } ListNode hair = new ListNode (-1 ); hair.next = head; for (int len = 1 ; len < length; len *= 2 ) { ListNode prev = hair, cur = hair.next; while (cur != null ) { ListNode l1 = cur; for (int i = 1 ; i < len && cur.next != null ; i++) { cur = cur.next; } ListNode l2 = cur.next; cur.next = null ; cur = l2; for (int i = 1 ; i < len && cur != null && cur.next != null ; i++) { cur = cur.next; } ListNode nex = null ; if (cur != null ) { nex = cur.next; cur.next = null ; } ListNode merged = merge(l1, l2); prev.next = merged; while (prev.next != null ) { prev = prev.next; } cur = nex; } } return hair.next; } private ListNode merge (ListNode head1, ListNode head2) { if (head1 == null ) return head2; if (head2 == null ) return head1; if (head1.val <= head2.val) { head1.next = merge(head1.next, head2); return head1; } else { head2.next = merge(head2.next, head1); return head2; } }
堆 数组中的第K个最大元素 215. 数组中的第K个最大元素 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public int findKthLargest (int [] nums, int k) { PPriorityQueue<Integer> minHeap = new PriorityQueue <>(k, (n1, n2) -> { return n1 - n2; }); for (int i = 0 ; i < k; i++) { minHeap.add(nums[i]); } for (int i = k; i < nums.length; i++) { Integer topNode = minHeap.peek(); if (nums[i] > topNode) { minHeap.poll(); minHeap.add(nums[i]); } } return minHeap.peek(); }
数据流的中位数 295. 数据流的中位数 - 力扣(LeetCode)
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 PriorityQueue<Integer> queMin; PriorityQueue<Integer> queMax; public MedianFinder () { queMin = new PriorityQueue <>((n1, n2) -> (n2 - n1)); queMax = new PriorityQueue <>((n1, n2) -> (n1 - n2)); } public void addNum (int num) { if (queMin.isEmpty()) { queMin.offer(num); } else if (num < queMin.peek()) { queMin.offer(num); if (queMin.size() > queMax.size() + 1 ) { queMax.offer(queMin.poll()); } } else { queMax.offer(num); if (queMax.size() > queMin.size()){ queMin.offer(queMax.poll()); } } } public double findMedian () { if (queMin.size() == queMax.size() + 1 ) { return queMin.peek(); } return (queMin.peek() + queMax.peek()) / 2.0 ; }
丑数 II 264. 丑数 II - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public int nthUglyNumber (int n) { int [] factors = new int []{2 , 3 , 5 }; Set<Long> seen = new HashSet <Long>(); PriorityQueue<Long> minHeap = new PriorityQueue <>(); seen.add(1L ); minHeap.offer(1L ); int ans = 0 ; for (int i = 0 ; i < n; i++) { long curr = minHeap.poll(); ans = (int ) curr; for (int factor : factors) { long next = curr * factor; if (seen.add(next)) { minHeap.offer(next); } } } return ans; }
三指针法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int nthUglyNumber (int n) { int [] ans = new int [n + 1 ]; ans[1 ] = 1 ; for (int i2 = 1 , i3 = 1 , i5 = 1 , i = 2 ; i <= n; i++) { int a = 2 * ans[i2]; int b = 3 * ans[i3]; int c = 5 * ans[i5]; int min = Math.min(a, Math.min(b, c)); if (min == a) i2++; if (min == b) i3++; if (min == c) i5++; ans[i] = min; } return ans[n]; }
树 递归的时间复杂度:目前不清楚
递归的空间复杂度:目前不清楚
树的题目首先要想的就是递归去解决,因为每个节点都有左子树和右子树这样相同的结构
遍历的话,一般dfs就是用递归,还有一个是bfs层序遍历,很多题目都是在遍历的基础上去做的
中序遍历二叉搜索树的话,是一个递增的数组
如果要修改树的结构,可能需要用到pre指针记录父节点位置
1、遍历
DFS :前序、中序、后序,用递归或者栈模拟(while条件 root != null || ! stack.isEmpty() )
BFS :层序,用队列模拟(while条件 ! queue.isEmpty() )
二叉树的前序遍历 144. 二叉树的前序遍历 - 力扣(LeetCode)
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public List<Integer> inorderTraversal (TreeNode root) { List<Integer> ans = new ArrayList <>(); Stack<TreeNode> S = new Stack <>(); while (root != null || !S.isEmpty()) { while (root != null ) { S.push(root); ans.add(root.val); root = root.left; } root = S.pop(); root = root.right; } return ans; }
二叉树的中序遍历 94. 二叉树的中序遍历 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 List<Integer> ans; public List<Integer> inorderTraversal (TreeNode root) { ans = new ArrayList <>(); dfs(root); return ans; } private void dfs (TreeNode root) { if (root == null ) return ; dfs(root.left); ans.add(root.val); dfs(root.right); }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public List<Integer> inorderTraversal (TreeNode root) { List<Integer> ans = new ArrayList <>(); Stack<TreeNode> S = new Stack <>(); while (root != null || !S.isEmpty()) { while (root != null ) { S.push(root); root = root.left; } root = S.pop(); ans.add(root.val); root = root.right; } return ans; }
二叉树的后序遍历 145. 二叉树的后序遍历 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 List<Integer> ans; public List<Integer> inorderTraversal (TreeNode root) { ans = new ArrayList <>(); dfs(root); return ans; } private void dfs (TreeNode root) { if (root == null ) return ; dfs(root.left); dfs(root.right); ans.add(root.val); }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public List<Integer> postorderTraversal (TreeNode root) { List<Integer> ans = new ArrayList <>(); Stack<TreeNode> S = new Stack <>(); while (root != null || !S.isEmpty()) { while (root != null ) { S.push(root); ans.add(root.val); root = root.right; } root = S.pop(); root = root.left; } Collections.reverse(ans); return ans; }
二叉树的层序遍历 102. 二叉树的层序遍历 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public List<List<Integer>> levelOrder (TreeNode root) { List<List<Integer>> res = new LinkedList <>(); if (root == null ) return res; LinkedList<TreeNode> queue = new LinkedList <>(); queue.add(root); while (!queue.isEmpty()) { List<Integer> ans = new LinkedList <>(); int size = queue.size(); for (int i = 0 ; i < size; i++) { TreeNode node = queue.poll(); ans.add(node.val); if (node.left != null ) queue.add(node.left); if (node.right != null ) queue.add(node.right); } res.add(new ArrayList <>(ans)); } return res; }
二叉树的右视图 199. 二叉树的右视图 - 力扣(LeetCode)
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 ``` ## 二叉树的锯齿形层序遍历 [103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)](https: ```java public List<List<Integer>> zigzagLevelOrder (TreeNode root) { List<List<Integer>> res = new LinkedList <>(); if (root == null )return res; LinkedList<TreeNode> queue = new LinkedList <>(); queue.add(root); boolean flag = false ; while (!queue.isEmpty()){ int size = queue.size(); LinkedList<Integer> ans = new LinkedList <>(); for (int i = 0 ; i < size; i++) { TreeNode node = queue.poll(); ans.add(node.val); if (node.left!=null ) queue.add(node.left); if (node.right!=null ) queue.add(node.right); } if (flag) Collections.reverse(ans); flag = !flag; res.add(new ArrayList <>(ans)); } return res; }
二叉搜索树中第K小的元素 230. 二叉搜索树中第K小的元素 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int count;int ans;public int kthSmallest (TreeNode root, int k) { count = k; dfs(root); return ans; } private void dfs (TreeNode root) { if (root == null ) return ; dfs(root.left); if (count == 0 ) { return ; } if (--count == 0 ) { ans = root.val; } dfs(root.right); }
迭代法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int kthSmallest (TreeNode root, int k) { Stack<TreeNode> S = new Stack <>(); while (root != null || !S.isEmpty()) { while (root != null ) { S.push(root); root = root.left; } root = S.pop(); if (--k == 0 ) { return root.val; } root = root.right; } return -1 ; }
二叉树的最大深度 104. 二叉树的最大深度 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 public int maxDepth (TreeNode root) { if (root == null ) return 0 ; int l = maxDepth(root.left); int r = maxDepth(root.right); return Math.max(l, r) + 1 ; }
二叉树的最近公共祖先 236. 二叉树的最近公共祖先 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 public TreeNode lowestCommonAncestor (TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if (left == null ) return right; if (right == null ) return left; return root; }
二叉搜索树的最近公共祖先 235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 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; } }
验证二叉树的前序序列化 用数组的方式来进行树的遍历,有点意思的
331. 验证二叉树的前序序列化 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int index = 0 ;String[] s; public boolean isValidSerialization (String preorder) { s = preorder.split("," ); dfs(); return s.length - 1 == index; } private void dfs () { if (index >= s.length) return ; if (Objects.equals(s[index], "#" )) return ; index++; dfs(); index++; dfs(); }
二叉树的序列化与反序列化 297. 二叉树的序列化与反序列化 - 力扣(LeetCode)
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 String str = "" ;public String serialize (TreeNode root) { rserialize(root); return str; } private void rserialize (TreeNode root) { if (root == null ) { str += "None," ; } else { str += str.valueOf(root.val) + "," ; rserialize(root.left); rserialize(root.right); } } public TreeNode deserialize (String data) { String[] dataArray = data.split("," ); LinkedList<String> dataList = new LinkedList <String>(Arrays.asList(dataArray)); return rdeserialize(dataList); } private TreeNode rdeserialize (LinkedList<String> dataList) { if (dataList.getFirst().equals("None" )){ dataList.removeFirst(); return null ; } TreeNode root = new TreeNode (Integer.parseInt(dataList.getFirst())); dataList.removeFirst(); root.left = rdeserialize(dataList); root.right = rdeserialize(dataList); return root; }
二叉搜索树与双向链表 https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=11179&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 LinkedList<TreeNode> nodeList = new LinkedList <>(); public TreeNode Convert (TreeNode pRootOfTree) { if (pRootOfTree == null ) return null ; inorder(pRootOfTree); for (int i = 0 ; i < nodeList.size() - 1 ; i++) { nodeList.get(i).right = nodeList.get(i + 1 ); nodeList.get(i + 1 ).left = nodeList.get(i); } return nodeList.get(0 ); } void inorder (TreeNode root) { if (root == null ) return ; inorder(root.left); nodeList.add(root); inorder(root.right); }
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 TreeNode head = null ;TreeNode prev = null ;public TreeNode Convert (TreeNode pRootOfTree) { if (pRootOfTree == null ) return null ; inorder(pRootOfTree); return head; } void inorder (TreeNode root) { if (root == null ) return ; inorder(root.left); if (prev == null ) { head = root; prev = root; } else { prev.right = root; root.left = prev; prev = root; } inorder(root.right); }
从前序与中序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
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 private Map<Integer, Integer> indexMap;public TreeNode buildTree (int [] preorder, int [] inorder) { int n = preorder.length; indexMap = new HashMap <Integer, Integer>(); for (int i = 0 ; i < n; i++) { indexMap.put(inorder[i], i); } return buildTree(preorder, inorder, 0 , preorder.length - 1 , 0 , inorder.length - 1 ); } public TreeNode buildTree (int [] preorder, int [] inorder, int pre_start, int pre_end, int in_start, int in_end) { if (pre_start > pre_end) { return null ; } int root_val = preorder[pre_start]; TreeNode root = new TreeNode (root_val); int index = indexMap.get(root_val); int leftNum = index - in_start; root.left = buildTree(preorder, inorder, pre_start + 1 , pre_start + leftNum, in_start, index - 1 ); root.right = buildTree(preorder, inorder, pre_start + leftNum + 1 , pre_end, index + 1 , in_end); return root; }
另一棵树的子树 572. 另一棵树的子树 - 力扣(LeetCode)
暴力递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public boolean isSubtree (TreeNode root, TreeNode subRoot) { return dfs(root, subRoot); } private boolean dfs (TreeNode s, TreeNode t) { if (s == null ) return false ; return check(s, t) || dfs(s.left, t) || dfs(s.right, t); } private boolean check (TreeNode s, TreeNode t) { if (s == null && t == null ) return true ; if (s == null || t == null || s.val != t.val) return false ; return check(s.left, t.left) && check(s.right, t.right); }
翻转二叉树 226. 翻转二叉树 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 public TreeNode invertTree (TreeNode root) { if (root == null ) return null ; TreeNode leftNode = root.left; TreeNode rightNode = root.right; root.left = rightNode; root.right = leftNode; invertTree(root.left); invertTree(root.right); return root; }
层序遍历法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public TreeNode invertTree (TreeNode root) { LinkedList<TreeNode> queue = new LinkedList <>(); if (root == null ) return null ; queue.add(root); while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0 ; i < size; i++) { TreeNode node = queue.poll(); TreeNode leftNode = node.left; TreeNode rightNode = node.right; node.left = rightNode; node.right = leftNode; if (node.right != null ) queue.add(node.right); if (node.left != null ) queue.add(node.left); } } return root; }
对称二叉树 101. 对称二叉树 - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public boolean isSymmetric (TreeNode root) { if (root == null ) return true ; return isSymmetric(root.left, root.right); } public boolean isSymmetric (TreeNode leftNode, TreeNode rightNode) { if (leftNode == null && rightNode == null ) return true ; if (leftNode == null || rightNode == null ) return false ; if (leftNode.val != rightNode.val) return false ; return isSymmetric(leftNode.left, rightNode.right) && isSymmetric(leftNode.right, rightNode.left); }
迭代法
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 public boolean isSymmetric (TreeNode root) { return check(root, root); } public boolean check (TreeNode u, TreeNode v) { LinkedList<TreeNode> queue = new LinkedList <TreeNode>(); queue.offer(u); queue.offer(v); while (!queue.isEmpty()) { u = queue.poll(); v = queue.poll(); if (u == null && v == null ) { continue ; } if ((u == null || v == null ) || (u.val != v.val)) { return false ; } queue.offer(u.left); queue.offer(v.right); queue.offer(u.right); queue.offer(v.left); } return true ; }
路径总和 112. 路径总和 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 public boolean hasPathSum (TreeNode root, int targetSum) { return dfs(root, targetSum); } public boolean dfs (TreeNode root, int targetSum) { if (root == null ) return false ; if (root.left == null && root.right == null ){ return root.val == targetSum; } return dfs(root.left, targetSum - root.val) || dfs(root.right, targetSum - root.val); }
路径总和 II 113. 路径总和 II - 力扣(LeetCode)
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 List<List<Integer>> res = new LinkedList <>(); LinkedList<TreeNode> path = new LinkedList <>(); public List<List<Integer>> pathSum (TreeNode root, int targetSum) { dfs(root, targetSum); return res; } public void dfs (TreeNode root, int targetSum) { if (root == null ) return ; path.add(root); if (root.left == null && root.right == null ) { if (root.val == targetSum) { LinkedList<Integer> ans = new LinkedList <>(); for (TreeNode treeNode : path) { ans.add(treeNode.val); } res.add(new ArrayList <>(ans)); } } dfs(root.left, targetSum - root.val); if (root.left != null ) path.removeLast(); dfs(root.right, targetSum - root.val); if (root.right != null ) path.removeLast(); }
二叉树中的最大路径和 124. 二叉树中的最大路径和 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int ans = Integer.MIN_VALUE;public int maxPathSum (TreeNode root) { dfs(root); return ans; } int dfs (TreeNode root) { if (root == null ) return 0 ; int leftVal = Math.max(dfs(root.left), 0 ); int rightVal = Math.max(dfs(root.right), 0 ); int maxRoad = root.val + leftVal + rightVal; ans = Math.max(ans, maxRoad); return root.val + Math.max(leftVal, rightVal); }
二叉树的直径 543. 二叉树的直径 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int ans = 1 ;public int diameterOfBinaryTree (TreeNode root) { depth(root); return ans - 1 ; } public int depth (TreeNode root) { if (root == null ) { return 0 ; } int left = depth(root.left); int right = depth(root.right); ans = Math.max(ans, left + right + 1 ); return Math.max(right, left) + 1 ; }
图 岛屿数量 nettee 的DFS题解无敌
200. 岛屿数量 - 力扣(LeetCode)
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 public int numIslands (char [][] grid) { int res = 0 ; int m = grid.length; int n = grid[0 ].length; for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (grid[i][j] == '1' ) { res++; dfs(grid, i, j); } } } return res; } private void dfs (char [][] grid, int i, int j) { if (i < 0 || j < 0 || i >= grid.length || j >= grid[0 ].length || grid[i][j] == '0' ) return ; grid[i][j] = '0' ; dfs(grid, i + 1 , j); dfs(grid, i - 1 , j); dfs(grid, i, j + 1 ); dfs(grid, i, j - 1 ); }
二分算法 坚持一个原则,可以是左闭右闭(下标从最小到最大)
每次循环都需要缩小查找的数组的范围,right = mid or right = mid - 1,但是left= mid会造成死循环(比如数组两个数的时候)
x 的平方根 69. x 的平方根 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int mySqrt (int x) { int l = 0 , r = x; while (l <= r) { int mid = (l + r) / 2 ; if ((long )mid * mid == x) { return mid; } else if ((long )mid * mid > x) { r = mid - 1 ; } else { l = mid + 1 ; } } return r; }
二分查找 704. 二分查找 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int search (int [] nums, int target) { int l = 0 , r = nums.length; while (l < r) { int mid = (l + r) / 2 ; if (nums[mid] == target) { return mid; } else if (nums[mid] > target) { r = mid; } else { l = mid + 1 ; } } return -1 ; }
搜索旋转排序数组 33. 搜索旋转排序数组 - 力扣(LeetCode)
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 public int search (int [] nums, int target) { int l = 0 , r = nums.length - 1 ; while (l < r) { int mid = (l + r + 1 ) / 2 ; if (nums[mid] >= nums[0 ]) { l = mid; } else { r = mid - 1 ; } } if (target >= nums[0 ]) { l = 0 ; } else { l = l + 1 ; r = nums.length - 1 ; } while (l < r) { int mid = (l + r) / 2 ; if (target > nums[mid]) { l = mid + 1 ; } else if (target <= nums[mid]) { r = mid; } } return nums[r] == target ? r : -1 ; }
寻找旋转排序数组中的最小值 II 154. 寻找旋转排序数组中的最小值 II - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 public int findMin (int [] nums) { int l = 0 ; int r = nums.length - 1 ; while (l < r) { int mid = l + (r - l) / 2 ; if (nums[mid] > nums[r]) l = mid + 1 ; else if (nums[mid] < nums[r]) r = mid; else r--; } return nums[l]; }
双指针
替换数组的两个位置的元素
比较两个位置的元素是否相等
移动零 283. 移动零 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void moveZeroes (int [] nums) { int l = 0 , r = 1 ; while (r < nums.length) { if (nums[l] == 0 ){ while (r < nums.length && nums[r] == 0 ) { r++; } if (r < nums.length){ nums[l] = nums[r]; nums[r] = 0 ; } } l++; r++; } }
合并两个有序数组 88. 合并两个有序数组 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void merge (int [] nums1, int m, int [] nums2, int n) { int p1 = m - 1 , p2 = n - 1 ; int tail = m + n - 1 ; int cur; while (p1 >= 0 || p2 >= 0 ) { if (p1 < 0 ) { cur = nums2[p2--]; } else if (p2 < 0 ) { cur = nums1[p1--]; } else if (nums1[p1] > nums2[p2]){ cur = nums1[p1--]; }else { cur = nums2[p2--]; } nums1[tail--] = cur; } }
按奇偶排序数组 905. 按奇偶排序数组 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public int [] sortArrayByParity(int [] nums) { int left = 0 , right = nums.length - 1 ; while (left < right) { while (left < nums.length && nums[left] % 2 == 0 ) { left++; } while (right >= 0 && nums[right] % 2 == 1 ) { right--; } if (left < right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; } left++; right--; } return nums; }
删除链表的倒数第 N 个结点 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public ListNode removeNthFromEnd (ListNode head, int n) { ListNode hair = new ListNode (-1 , head); ListNode slow = hair, fast = hair; while (n-- >= 0 ) { fast = fast.next; } while (fast != null ) { fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return hair.next; }
环形链表 II 142. 环形链表 II - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public ListNode detectCycle (ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null ) { slow = slow.next; fast = fast.next.next; if (slow == fast) { ListNode p1 = head; ListNode p2 = slow; while (p1 != p2) { p1 = p1.next; p2 = p2.next; } return p1; } } return null ; }
三数之和 15. 三数之和 - 力扣(LeetCode)
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 public List<List<Integer>> threeSum (int [] nums) { List<List<Integer>> res = new ArrayList (); Arrays.sort(nums); for (int i = 0 ; i < nums.length; i++){ if (nums[i] > 0 ) return res; if (i > 0 && nums[i] == nums[i - 1 ]) { continue ; } int left = i + 1 ; int right = nums.length - 1 ; while (left < right){ int sum = nums[i] + nums[left] + nums[right]; if (sum < 0 ) left++; else if (sum > 0 ) right--; else { res.add(Arrays.asList(nums[i], nums[left], nums[right])); while (right > left && nums[right] == nums[right - 1 ]) right--; while (right > left && nums[left] == nums[left + 1 ]) left++; left++; right--; } } } return res; }
滑动窗口
字符串的滑动窗口问题【也可以理解为字串的问题】:
只有一个字符串:窗口内没有重复
有两个字符串需要比对:找覆盖了目标串的窗口、和目标串相同字母的窗口
数组的滑动窗口问题【也可以理解为子数组的问题】:窗口内的最大值、窗口的目标值为k
无重复字符的最长子串 3. 无重复字符的最长子串 - 力扣(LeetCode)
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 public int lengthOfLongestSubstring (String s) { Set<Character> map = new HashSet <>(); int left = 0 , right = 0 ; int len = 0 ; int ans = 0 ; char [] chars = s.toCharArray(); while (right < chars.length) { if (map.contains(chars[right])) { while (chars[left] != chars[right]) { map.remove(chars[left]); left++; len--; } left++; } else { map.add(chars[right]); len++; } ans = Math.max(ans, len); right++; } return ans; }
滑动窗口最大值 239. 滑动窗口最大值 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public int [] maxSlidingWindow(int [] nums, int k) { Deque<Integer> queue = new LinkedList <>(); int [] res = new int [nums.length - k + 1 ]; for (int i = 0 ; i < nums.length; i++) { while (!queue.isEmpty() && queue.peekFirst() < i - (k - 1 )) { queue.pollFirst(); } while (!queue.isEmpty() && nums[i] > nums[queue.peekLast()]) { queue.pollLast(); } queue.offer(i); if (i >= k - 1 ) { res[i - (k - 1 )] = nums[queue.peekFirst()]; } } return res; }
找到字符串中所有字母异位词 438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
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 public List<Integer> findAnagrams (String s, String p) { int sLen = s.length(), pLen = p.length(); if (sLen < pLen) { return new ArrayList <Integer>(); } List<Integer> ans = new ArrayList <Integer>(); int [] sCount = new int [26 ]; int [] pCount = new int [26 ]; for (int i = 0 ; i < pLen; ++i) { ++sCount[s.charAt(i) - 'a' ]; ++pCount[p.charAt(i) - 'a' ]; } if (Arrays.equals(sCount, pCount)) { ans.add(0 ); } for (int i = 0 ; i < sLen - pLen; ++i) { --sCount[s.charAt(i) - 'a' ]; ++sCount[s.charAt(i + pLen) - 'a' ]; if (Arrays.equals(sCount, pCount)) { ans.add(i + 1 ); } } return ans; }
最小覆盖子串 76. 最小覆盖子串 - 力扣(LeetCode)
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 public String minWindow (String s, String t) { int [] need = new int [128 ]; for (int i = 0 ; i < t.length(); i++) { need[t.charAt(i)]++; } int left = 0 , right = 0 ; int start = 0 ; int len = Integer.MAX_VALUE; int count = t.length(); while (right < s.length()) { char c = s.charAt(right); if (need[c] > 0 ) { count--; } need[c]--; if (count == 0 ) { while (left < right && need[s.charAt(left)] < 0 ) { need[s.charAt(left)]++; left++; } if (right - left + 1 < len) { len = right - left + 1 ; start = left; } need[s.charAt(left)]++; left++; count++; } right++; } return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); }
回溯算法 回溯算法的模板 循环的次数
确定返回的条件
剪枝优化
1 2 3 4 5 6 7 8 9 10 11 12 void backtracking(参数) { if (终止条件) { 存放结果; return; } for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); // 递归 回溯,撤销处理结果 } }
树枝去重和数层去重,used[i - 1]为true就是树枝,false就是数层
排列:
组合:
我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 ,216.组合总和III 。
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:17.电话号码的字母组合
去重问题:数组排序才能去重
有startIndex才能树枝去重,没有的话只能数层去重
used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
used[i - 1] == false,说明同一树层candidates[i - 1]使用过
子集:
分割字符串:和组合问题类似
棋盘:
括号生成 22. 括号生成 - 力扣(LeetCode)
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 List<String> res = new ArrayList <>(); StringBuilder sb = new StringBuilder ();public List<String> generateParenthesis (int n) { backTracking(0 , 0 , n); return res; } public void backTracking (int left, int right, int n) { if (sb.length() == 2 * n) { res.add(new String (sb)); return ; } if (left < n) { sb.append("(" ); backTracking(left + 1 , right, n); sb.deleteCharAt(sb.length() - 1 ); } if (left > right) { sb.append(")" ); backTracking(left, right + 1 , n); sb.deleteCharAt(sb.length() - 1 ); } }
全排列 46. 全排列 - 力扣(LeetCode)
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 List<List<Integer>> res = new ArrayList <>(); LinkedList<Integer> path = new LinkedList <>(); boolean [] used;public List<List<Integer>> permute (int [] nums) { used = new boolean [nums.length]; backTraveling(nums); return res; } void backTraveling (int [] nums) { if (path.size() == nums.length){ res.add(new ArrayList <>(path)); return ; } for (int i = 0 ; i < nums.length; i++) { if (used[i]) continue ; used[i] = true ; path.add(nums[i]); backTraveling(nums); path.removeLast(); used[i] = false ; } }
全排列 II 47. 全排列 II - 力扣(LeetCode)
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 List<List<Integer>> res = new ArrayList <>(); LinkedList<Integer> path = new LinkedList <>(); boolean [] used;public List<List<Integer>> permuteUnique (int [] nums) { used = new boolean [nums.length]; Arrays.sort(nums); backTraveling(nums); return res; } void backTraveling (int [] nums) { if (path.size() == nums.length) { res.add(new ArrayList <>(path)); return ; } for (int i = 0 ; i < nums.length; i++) { if (used[i]) continue ; if (i > 0 && nums[i] == nums[i - 1 ] && !used[i - 1 ]) continue ; used[i] = true ; path.add(nums[i]); backTraveling(nums); path.removeLast(); used[i] = false ; } }
单词搜索 79. 单词搜索 - 力扣(LeetCode)
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 public boolean exist (char [][] board, String word) { for (int i = 0 ; i < board.length; i++) { for (int j = 0 ; j < board[0 ].length; j++) { if (backTracking(board, word, i, j, 0 )) return true ; } } return false ; } boolean backTracking (char [][] board, String word, int i, int j, int index) { if (i < 0 || i >= board.length || j < 0 || j >= board[0 ].length || word.charAt(index) != board[i][j]) return false ; if (index == word.length() - 1 ) { return true ; } boolean ans; char c = board[i][j]; board[i][j] = ' ' ; ans = backTracking(board, word, i + 1 , j, index + 1 ) || backTracking(board, word, i - 1 , j, index + 1 ) || backTracking(board, word, i, j + 1 , index + 1 ) || backTracking(board, word, i, j - 1 , index + 1 ); board[i][j] = c; return ans; }
机器人的运动范围 LCR 130. 衣橱整理 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 boolean [][] visited;public int wardrobeFinishing (int m, int n, int cnt) { visited = new boolean [m][n]; for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (i / 10 + i % 10 + j / 10 + j % 10 > cnt) { visited[i][j] = true ; } } } return dfs(0 , 0 , m, n); } int dfs (int i, int j, int m, int n) { if (i >= m || j >= n || visited[i][j]) { return 0 ; } visited[i][j] = true ; return 1 + dfs(i + 1 , j, m, n) + dfs(i, j + 1 , m, n); }
复原 IP 地址 93. 复原 IP 地址 - 力扣(LeetCode)
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 List<String> ans; public List<String> restoreIpAddresses (String s) { ans = new LinkedList <>(); backTraveling(s, 0 , 0 ); return ans; } void backTraveling (String s, int start, int pointNum) { if (pointNum == 3 ) { if (isValid(s, start, s.length() - 1 )) { ans.add(s); } return ; } for (int i = start; i < s.length(); i++) { if (!isValid(s, start, i)) break ; s = s.substring(0 , i + 1 ) + "." + s.substring(i + 1 ); pointNum++; backTraveling(s, i + 2 , pointNum); pointNum--; s = s.substring(0 , i + 1 ) + s.substring(i + 2 ); } } private boolean isValid (String s, int start, int end) { if (start > end) { return false ; } if (s.charAt(start) == '0' && start != end) { return false ; } int num = 0 ; for (int i = start; i <= end; i++) { if (s.charAt(i) > '9' || s.charAt(i) < '0' ) { return false ; } num = num * 10 + (s.charAt(i) - '0' ); if (num > 255 ) { return false ; } } return true ; }
贪心算法 局部最优解堆叠成全局最优解
动态规划 将问题拆成若干份小问题
确定dp的含义
用0边界确定初始化
列出状态方程
优化
爬楼梯 70. 爬楼梯 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 public int climbStairs (int n) { int [] dp = new int [n + 2 ]; dp[1 ] = 1 ; dp[2 ] = 2 ; for (int i = 3 ; i <= n; i++) { dp[i] = dp[i - 1 ] + dp[i - 2 ]; } return dp[n]; }
编辑距离 72. 编辑距离 - 力扣(LeetCode)
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 public int minDistance (String word1, String word2) { int m = word1.length(); int n = word2.length(); int [][] dp = new int [m + 1 ][n + 1 ]; for (int i = 0 ; i <= m; i++) { dp[i][0 ] = i; } for (int j = 0 ; j <= n; j++) { dp[0 ][j] = j; } char [] arr1 = word1.toCharArray(); char [] arr2 = word2.toCharArray(); for (int i = 1 ; i <= m; i++) { for (int j = 1 ; j <= n; j++) { if (arr1[i - 1 ] == arr2[j - 1 ]) { dp[i][j] = dp[i - 1 ][j - 1 ]; } else { dp[i][j] = Math.min(Math.min(dp[i - 1 ][j - 1 ], dp[i][j - 1 ]), dp[i - 1 ][j]) + 1 ; } } } return dp[m][n]; }
最长公共子序列 1143. 最长公共子序列 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public int longestCommonSubsequence (String text1, String text2) { int m = text1.length(); int n = text2.length(); int [][] dp = new int [m + 1 ][n + 1 ]; char [] s1 = text1.toCharArray(); char [] s2 = text2.toCharArray(); for (int i = 1 ; i <= m; i++) { for (int j = 1 ; j <= n; j++) { if (s1[i - 1 ] == s2[j - 1 ]) { dp[i][j] = dp[i - 1 ][j - 1 ] + 1 ; } else { dp[i][j] = Math.max(dp[i - 1 ][j - 1 ], Math.max(dp[i - 1 ][j], dp[i][j - 1 ])); } } } return dp[m][n]; }
统计结果概率 LCR 185. 统计结果概率 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public double [] statisticsProbability(int num) { double [] pre = {1 / 6d , 1 / 6d , 1 / 6d , 1 / 6d , 1 / 6d , 1 / 6d }; for (int i = 2 ; i <= num; i++) { double [] cur = new double [6 * i - (i - 1 )]; for (int j = 0 ; j < pre.length; j++) { for (int k = 0 ; k < 6 ; k++) { cur[j + k] += pre[j] * (1 / 6d ); } } pre = cur; } return pre; }
整数拆分 343. 整数拆分 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int integerBreak (int n) { int [] dp = new int [n + 1 ]; dp[2 ] = 1 ; for (int i = 3 ; i <= n; i++) { for (int j = 1 ; j <= i - j; j++) { dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j])); } } return dp[n]; }
解码方法 91. 解码方法 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int numDecodings (String s) { int [] dp = new int [s.length() + 1 ]; dp[0 ] = 1 ; for (int i = 1 ; i <= s.length(); i++) { if (s.charAt(i - 1 ) != '0' ) { dp[i] += dp[i - 1 ]; } if (i > 1 && s.charAt(i - 2 ) != '0' && ((s.charAt(i - 2 ) - '0' ) * 10 + (s.charAt(i - 1 ) - '0' )) <= 26 ) { dp[i] += dp[i - 2 ]; } } return dp[s.length()]; }
珠宝的最高价值 LCR 166. 珠宝的最高价值 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 public int jewelleryValue (int [][] frame) { int m = frame.length, n = frame[0 ].length; int [][] dp = new int [m + 1 ][n + 1 ]; for (int i = 1 ; i <= m; i++) { for (int j = 1 ; j <= n; j++) { dp[i][j] = Math.max(dp[i - 1 ][j], dp[i][j - 1 ]) + frame[i - 1 ][j - 1 ]; } } return dp[m][n]; }
打家劫舍 股票 买卖股票的最佳时机 121. 买卖股票的最佳时机 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int maxProfit (int [] prices) { int [][] dp = new int [prices.length][2 ]; dp[0 ][0 ] = -prices[0 ]; dp[0 ][1 ] = 0 ; for (int i = 1 ; i < prices.length; i++) { dp[i][0 ] = Math.max(dp[i - 1 ][0 ], - prices[i]); dp[i][1 ] = Math.max(dp[i - 1 ][1 ], dp[i - 1 ][0 ] + prices[i]); } return dp[prices.length - 1 ][1 ]; }
子序列,子数组 一个序列 or 数组,可能和前面任何一个位置的状态都有关
两个序列 or 数组,只和 dp[i - 1][j - 1]
、dp[i][j - 1]
、dp[i - 1][j]
有关
dp[i][j]
表示的意思是s的前i个字母中匹配t的前j个字母的字母个数,或者是总数
最长递增子序列 300. 最长递增子序列 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int lengthOfLIS (int [] nums) { int [] dp = new int [nums.length]; int ans = Integer.MIN_VALUE; Arrays.fill(dp, 1 ); for (int i = 1 ; i < nums.length; i++) { for (int j = 0 ; j < i; j++) { if (nums[i] > nums[j]) { dp[i] = Math.max(dp[j] + 1 , dp[i]); } } ans = Math.max(ans, dp[i]); } return ans; }
最大子数组和 53. 最大子数组和 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 public int maxSubArray (int [] nums) { int [] dp = new int [nums.length]; dp[0 ] = nums[0 ]; int res = dp[0 ]; for (int i = 1 ; i < nums.length; i++) { dp[i] = Math.max(dp[i - 1 ] + nums[i], nums[i]); res = Math.max(res, dp[i]); } return res; }
1 2 3 4 5 6 7 8 9 10 public int maxSubArray (int [] nums) { int x = nums[0 ]; int res = nums[0 ]; for (int i = 1 ; i < nums.length; i++) { x = Math.max(x + nums[i], nums[i]); res = Math.max(x, res); } return res; }
数位dp 数字 1 的个数 233. 数字 1 的个数 - 力扣(LeetCode)
密码锁法,用 cur 区分左右两边的数字
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 public int countDigitOne (int n) { int res = 0 ; int high = n / 10 ; int cur = n % 10 ; int low = 0 ; int digit = 1 ; while (high != 0 || cur != 0 ) { if (cur == 0 ) { res += high * digit; } else if (cur == 1 ) { res += high * digit + low + 1 ; } else { res += (high + 1 ) * digit; } low += cur * digit; cur = high % 10 ; high /= 10 ; digit *= 10 ; } return res; }
排序 冒泡排序 1 2 3 4 5 6 7 8 9 10 11 12 13 for (int i = 0; i < 10; i++) { for (int j = 1; j < 10 - i; j++) { if (nums[j - 1] > nums[j]) { swap(nums, j - 1, j); } } } private static void swap(int[] nums, int i, int j) { int temp = nums[i] ^ nums[j]; nums[i] = temp ^ nums[i]; nums[j] = temp ^ nums[j]; }
快速排序 以第一个数为基准的写法
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 private static void quicksort(int[] nums) { sort(nums, 0, nums.length - 1); } private static void sort(int[] nums, int l, int r) { if (l >= r) return; // 递归排序基数 int index = partition(nums, l, r); // 递归排序基数左边的数组 sort(nums, l, index - 1); // 递归排序基数右边的数组 sort(nums, index + 1, r); } // 递归排序基数 private static int partition(int[] nums, int l, int r) { // 第一个数最为基准数 int temp = nums[l]; int i = l, j = r; while (i < j) { // 找到第一个比temp小的数字 while (nums[j] >= temp && i < j) { j--; } // 找到第一个比temp大的数字 while (nums[i] <= temp && i < j) { i++; } swap(nums, i, j); } // 将基准数交换到合适的位置,如果数组本身有序,可能自己和自己交换 swap(nums, l, i); return i; } private static void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
三路快排优化 前端学习数据结构与算法系列(八):快速排序与三路快排-腾讯云开发者社区-腾讯云 (tencent.com)
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 public int [] sortArray(int [] nums) { quickSort(nums, 0 , nums.length - 1 ); return nums; } private void quickSort (int [] nums, int l, int r) { if (l >= r) return ; int [] index = partition(nums, l, r); quickSort(nums, l, index[0 ]); quickSort(nums, index[1 ], r); } private int [] partition(int [] nums, int l, int r) { int base = nums[l]; int lt = l, gt = r + 1 ; for (int i = l + 1 ; i < gt; ) { if (nums[i] == base) { i++; } else if (nums[i] > base) { swap(nums, gt - 1 , i); gt--; } else { swap(nums, lt + 1 , i); lt++; i++; } } swap(nums, l, lt); lt--; return new int []{lt, gt}; } void swap (int [] nums, int left, int right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = 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 31 32 33 34 35 36 37 38 39 public static void gbSort(int[] nums){ sort(nums, 0, nums.length - 1); } public static void sort(int[] nums, int l, int r) { if (l >= r) return; int mid = l + (r - l) / 2; // 分 sort(nums, l, mid); sort(nums, mid + 1, r); // 治 merge(nums, l, mid, r); } private static void merge(int[] nums, int l, int mid, int r) { int[] temp = new int[nums.length]; int i = l, j = mid + 1; // 区间的左边界 int index = l; // 合并子数组,l 到 mid 是左数组,mid + 1 到 r 是右数组 while (i <= mid && j <= r) { if (nums[i] < nums[j]) { temp[index++] = nums[i++]; } else { temp[index++] = nums[j++]; } } while (i <= mid) { temp[index++] = nums[i++]; } while (j <= r) { temp[index++] = nums[j++]; } // 代替原来这个区间的的无序子数组 for (int k = l; k <= r; k++) { nums[k] = temp[k]; } }
进制和位运算 二进制中1的个数 191. 位1的个数 - 力扣(LeetCode)
循环遍历法
1 2 3 4 5 6 7 8 public int hammingWeight (int n) { int count = 0 ; for (int i = 0 ; i < 32 ; i++) { if ((n & (1 << i)) != 0 ) count++; } return count; }
位运算优化
1 2 3 4 5 6 7 8 9 10 public int hammingWeight (int n) { int count = 0 ; while (n != 0 ) { n &= (n - 1 ); count++; } return count; }
Pow(x, n) 50. Pow(x, n) - 力扣(LeetCode)
递归法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public double myPow (double x, int n) { long N = n; return N > 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N); } private double quickMul (double x, long N) { if (N == 0 ) return 1.0 ; double y = quickMul(x, N / 2 ); if (N % 2 == 0 ) { return y * y; } else { return y * y * x; } }
二进制拆解法
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 public double myPow (double x, int n) { long N = n; return N > 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N); } private double quickMul (double x, long N) { double ans = 1.0 ; double x_contribution = x; while (N > 0 ) { if (N % 2 == 1 ) { ans *= x_contribution; } x_contribution *= x_contribution; N /= 2 ; } return ans; } public double myPow (double x, int n) { long N = n; return N > 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N); } private double quickMul (double x, long N) { double ans = 1.0 ; double x_contribution = x; while (N > 0 ) { if ((N & 1 ) == 1 ) { ans *= x_contribution; } x_contribution *= x_contribution; N >>= 1 ; } return ans; }
只出现一次的数字 III 260. 只出现一次的数字 III - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int [] singleNumber(int [] nums) { int xor = 0 ; for (int num : nums) { xor ^= num; } int lsb = xor & (-xor); int ans1 = 0 , ans2 = 0 ; for (int num : nums) { if ((num & lsb) != 0 ) { ans1 ^= num; } else { ans2 ^= num; } } return new int []{ans1, ans2}; }
其它 轮转数组 189. 轮转数组 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void rotate (int [] nums, int k) { k %= nums.length; reverse(nums, 0 , nums.length - 1 ); reverse(nums, 0 , k - 1 ); reverse(nums, k, nums.length - 1 ); } public void reverse (int [] nums, int start, int end) { while (start < end) { int temp = nums[start]; nums[start] = nums[end]; nums[end] = temp; start++; end--; } }
比较版本号 165. 比较版本号 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public int compareVersion (String version1, String version2) { String[] ss1 = version1.split("\\." ), ss2 = version2.split("\\." ); int n = ss1.length, m = ss2.length; int i = 0 , j = 0 ; while (i < n || j < m) { int a = 0 , b = 0 ; if (i < n) a = Integer.parseInt(ss1[i++]); if (j < m) b = Integer.parseInt(ss2[j++]); if (a != b) return a > b ? 1 : -1 ; } return 0 ; }
文物朝代判断 LCR 186. 文物朝代判断 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 10 11 12 13 public boolean checkDynasty (int [] places) { Arrays.sort(places); int count = 0 ; for (int i = 0 ; i < places.length - 1 ; i++) { if (places[i] == 0 ) count++; else if (places[i] == places[i + 1 ]) return false ; } return places[4 ] - places[count] <= 4 ; }
设计机械累加器 LCR 189. 设计机械累加器 - 力扣(LeetCode)
1 2 3 4 public int mechanicalAccumulator (int target) { boolean x = target > 1 && (target += mechanicalAccumulator(target - 1 )) > 0 ; return target; }
破冰游戏 LCR 187. 破冰游戏 - 力扣(LeetCode)
1 2 3 4 5 6 7 8 9 public int iceBreakingGame (int num, int target) { int ans = 0 ; for (int i = 2 ; i <= num; i++) { ans = (ans + target) % i; } return ans; }
多数元素 169. 多数元素 - 力扣(LeetCode)
占领高地法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public int majorityElement (int [] nums) { int ans = 0 ; int count = 0 ; for (int i = 0 ; i < nums.length; i++){ if (count == 0 ){ ans = nums[i]; } if (ans == nums[i]){ count++; }else { count--; } } return ans; }
多数元素 II 229. 多数元素 II - 力扣(LeetCode)
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 public List<Integer> majorityElement (int [] nums) { int element1 = 0 ; int element2 = 0 ; int count1 = 0 ; int count2 = 0 ; for (int num : nums) { if (count1 > 0 && num == element1) { count1++; } else if (count2 > 0 && num == element2) { count2++; } else if (count1 == 0 ) { element1 = num; count1++; } else if (count2 == 0 ) { element2 = num; count2++; } else { count1--; count2--; } } int cnt1 = 0 ; int cnt2 = 0 ; for (int num : nums) { if (count1 > 0 && num == element1) { cnt1++; } if (count2 > 0 && num == element2) { cnt2++; } } List<Integer> res = new ArrayList <>(); if (count1 > 0 && cnt1 > nums.length / 3 ) { res.add(element1); } if (count2 > 0 && cnt2 > nums.length / 3 ) { res.add(element2); } return res; }