一、数组
88. 合并两个有序数组
public void merge(int[] nums1, int m, int[] nums2, int n) {int p1 = 0, p2 = 0;int[] sorted = new int[m + n];while (p1 < m || p2 < n) {int current;if (p1 == m) {current = nums2[p2++];} else if (p2 == n) {current = nums1[p1++];} else if (nums1[p1] < nums2[p2]) {current = nums1[p1++];} else {current = nums2[p2++];}sorted[p1 + p2 - 1] = current;}for (int i = 0; i < sorted.length; ++i) {nums1[i] = sorted[i];}}
27. 移除元素
public int removeElement(int[] nums, int val) {int left = 0;for (int right = 0; right < nums.length; ++right) {if (nums[right] != val) {if (left != right) {nums[left] = nums[right];}left++;}}return left;}
26. 删除有序数组中的重复项
public int removeDuplicates(int[] nums) {int i = 1;for (int j = 1; j < nums.length; ++j) {if (nums[i - 1] != nums[j]) {nums[i] = nums[j];i++;}}return i;}
80. 删除有序数组中的重复项 II
public int removeDuplicates(int[] nums) {if (nums.length < 2) {return nums.length;}int i = 2;for (int j = 2; j < nums.length; ++j) {if (nums[i - 2] != nums[j]) {nums[i] = nums[j];i++;}}return i;}
189. 轮转数组
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);}private void reverse(int[] nums, int start, int end) {while (start < end) {int tmp = nums[start];nums[start] = nums[end];nums[end] = tmp;start++;end--;}}
15. 三数之和
public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();if (nums.length == 0) {return result;}Arrays.sort(nums);for (int k = 0; k < nums.length - 2; ++k) {if (k > 0 && nums[k - 1] == nums[k]) {continue;}int i = k + 1, j = nums.length - 1;while (i < j) {int sum = nums[k] + nums[i] + nums[j];if (sum > 0) {while (i < j && nums[j] == nums[--j]) ;} else if (sum < 0) {while (i < j && nums[i] == nums[++i]) ;} else {result.add(Arrays.asList(nums[k], nums[i], nums[j]));while (i < j && nums[i] == nums[++i]) ;while (i < j && nums[j] == nums[--j]) ;}}}return result;}
66. 加一
public int[] plusOne(int[] digits) {for (int i = digits.length - 1; i >= 0; --i) {digits[i] = (digits[i] + 1) % 10;if (digits[i] != 0) {return digits;}}digits = new int[digits.length + 1];digits[0] = 1;return digits;}
380. O(1) 时间插入、删除和获取随机元素
class RandomizedSet {private List<Integer> nums;private Map<Integer, Integer> indices;private Random random;public RandomizedSet() {this.nums = new ArrayList<>();this.indices = new HashMap<>();this.random = new Random();}public boolean insert(int val) {if (indices.containsKey(val)) {return false;}int index = nums.size();nums.add(val);indices.put(val, index);return true;}public boolean remove(int val) {if (!indices.containsKey(val)) {return false;}int index = indices.get(val);int last = nums.get(nums.size() - 1);nums.set(index, last);indices.put(last, index);nums.remove(nums.size() - 1);indices.remove(val);return true;}public int getRandom() {int randomIndex = random.nextInt(nums.size());return nums.get(randomIndex);}
}
238. 除自身以外数组的乘积
public int[] productExceptSelf(int[] nums) {int[] left = new int[nums.length];int[] right = new int[nums.length];left[0] = 1;for (int i = 1; i < nums.length; ++i) {left[i] = left[i - 1] * nums[i - 1];}right[nums.length - 1] = 1;for (int i = nums.length - 2; i >= 0; --i) {right[i] = right[i + 1] * nums[i + 1];}int[] result = new int[nums.length];for (int i = 0; i < nums.length; ++i) {result[i] = left[i] * right[i];}return result;}
9. 回文数
public boolean isPalindrome(int x) {if (x < 0 || (x % 10 == 0 && x != 0)) {return false;}int revertedNumber = 0;while (x > revertedNumber) {revertedNumber = revertedNumber * 10 + x % 10;x /= 10;}return x == revertedNumber || x == revertedNumber / 10;}
11. 盛最多水的容器
public int maxArea(int[] height) {int maxArea = 0;for (int i = 0, j = height.length - 1; i < j; ) {int minHeight = height[i] < height[j] ? height[i++] : height[j--];maxArea = Math.max(maxArea, minHeight * (j - i + 1));}return maxArea;}
31. 下一个排列
思路:
- 先找出最大的索引i满足nums[i]<nums[i+1],如果不存在,就翻转整个数组
- 再找出另一个最大索引j满足nums[j]>nums[i]
- 交换nums[i]和nums[j]
- 最后翻转nums[i+1:]
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 (nums[i] >= nums[j]) {j--;}swap(nums, i, j);}reverse(nums, i + 1);}private void swap(int[] nums, int i, int j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}private void reverse(int[] nums, int i) {int j = nums.length - 1;while (i < j) {swap(nums, i, j);i++;j--;}}
二、字符串
344. 反转字符串
public void reverseString(char[] s) {int i = 0, j = s.length - 1;while (i < j) {char tmp = s[i];s[i] = s[j];s[j] = tmp;i++;j--;}}
14. 最长公共前缀
public String longestCommonPrefix(String[] strs) {if (strs == null || strs.length == 0) {return "";}for (int i = 0; i < strs[0].length(); ++i) {char c = strs[0].charAt(i);for (int j = 1; j < strs.length; ++j) {if (i == strs[j].length() || strs[j].charAt(i) != c) {return strs[0].substring(0, i);}}}return strs[0];}
392. 判断子序列
public boolean isSubsequence(String s, String t) {int i = 0, j = 0;while (i < s.length() && j < t.length()) {if (s.charAt(i) == t.charAt(j)) {i++;}j++;}return i >= s.length();}
58. 最后一个单词的长度
public int lengthOfLastWord(String s) {int end = s.length() - 1;while (end >= 0 && s.charAt(end) == ' ') {end--;}if (end < 0) {return 0;}int start = end;while (start >= 0 && s.charAt(start) != ' ') {start--;}return end - start;}
151. 反转字符串中的单词
public String reverseWords(String s) {String[] strs = s.trim().split(" ");StringBuilder res = new StringBuilder();for (int i = strs.length - 1; i >= 0; i--) {if (strs[i].equals("")) {continue;}res.append(strs[i] + " ");}return res.toString().trim();}
三、链表
常用解法及操作:
- 快慢指针
- 使用dummyNode
- 链表反转
- 找链表的中点
- 获取链表节点的个数
2. 两数相加
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(-1);ListNode current = dummy;int carry = 0;while (l1 != null || l2 != null) {int p = l1 == null ? 0 : l1.val;int q = l2 == null ? 0 : l2.val;int sum = p + q + carry;carry = sum / 10;current.next = new ListNode(sum % 10);current = current.next;if (l1 != null) {l1 = l1.next;}if (l2 != null) {l2 = l2.next;}}if (carry > 0) {current.next = new ListNode(carry);}return dummy.next;}
21. 合并两个有序链表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(-1);ListNode current = dummy;while (l1 != null && l2 != null) {if (l1.val < l2.val) {current.next = l1;l1 = l1.next;} else {current.next = l2;l2 = l2.next;}current = current.next;}if (l1 != null) {current.next = l1;}if (l2 != null) {current.next = l2;}return dummy.next;}
19. 删除链表的倒数第 N 个结点
public ListNode removeNthFromEnd(ListNode head, int n) {ListNode fast = head, slow = head;for (int i = 0; i < n + 1; ++i) {if (fast == null) {return head.next;}fast = fast.next;}while (fast != null) {fast = fast.next;slow = slow.next;}slow.next = slow.next.next;return head;}
160. 相交链表
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode pa = headA, pb = headB;while (pa != pb) {pa = pa == null ? headB : pa.next;pb = pb == null ? headA : pb.next;}return pa;}
83. 删除排序链表中的重复元素
public ListNode deleteDuplicates(ListNode head) {ListNode current = head;while (current != null && current.next != null) {if (current.val == current.next.val) {current.next = current.next.next;} else {current = current.next;}}return head;}
82. 删除排序链表中的重复元素 II
public ListNode deleteDuplicates(ListNode head) {if (head == null) {return head;}ListNode dummy = new ListNode(-1, head);ListNode current = dummy;while (current.next != null && current.next.next != null) {if (current.next.val == current.next.next.val) {int x = current.next.val;while (current.next != null && current.next.val == x) {current.next = current.next.next;}} else {current = current.next;}}return dummy.next;}
141. 环形链表
public boolean hasCycle(ListNode head) {ListNode fast = head, slow = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;if (fast == slow) {return true;}}return false;}
142. 环形链表 II
public ListNode detectCycle(ListNode head) {ListNode fast = head, slow = head;boolean hasCycle = false;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;if (fast == slow) {hasCycle = true;break;}}if (!hasCycle) {return null;}fast = head;while (fast != slow) {fast = fast.next;slow = slow.next;}return slow;}
206. 反转链表
public ListNode reverseList(ListNode head) {ListNode pre = null, next = null;while (head != null) {next = head.next;head.next = pre;pre = head;head = next;}return pre;}
92. 反转链表 II
public ListNode reverseBetween(ListNode head, int left, int right) {ListNode dummy = new ListNode(-1, head);ListNode preStart = dummy;for (int i = 0; i < left - 1; ++i) {preStart = preStart.next;}ListNode start = preStart.next;ListNode end = start;for (int i = 0; i < right - left; ++i) {end = end.next;}ListNode endNext = end.next;preStart.next = null;end.next = null;preStart.next = reverse(start);start.next = endNext;return dummy.next;}private ListNode reverse(ListNode node) {ListNode pre = null, next = null;while (node != null) {next = node.next;node.next = pre;pre = node;node = next;}return pre;}
25. K 个一组翻转链表
public ListNode reverseKGroup(ListNode head, int k) {ListNode dummy = new ListNode(-1, head);ListNode pre = dummy, end = dummy;while (end.next != null) {for (int i = 0; i < k && end != null; ++i) {end = end.next;}if (end == null) {break;}ListNode start = pre.next, endNext = end.next;pre.next = null;end.next = null;pre.next = reverse(start);start.next = endNext;pre = start;end = start;}return dummy.next;}private ListNode reverse(ListNode node) {ListNode pre = null, next = null;while (node != null) {next = node.next;node.next = pre;pre = node;node = next;}return pre;}
61. 旋转链表
public ListNode rotateRight(ListNode head, int k) {if (head == null || head.next == null || k == 0) {return head;}ListNode current = head;int len = 0;while (current != null) {current = current.next;len++;}k = k % len;if (k == 0) {return head;}ListNode fast = head, slow = head;for (int i = 0; i < k + 1; ++i) {fast = fast.next;}while (fast != null) {fast = fast.next;slow = slow.next;}ListNode newHead = slow.next;slow.next = null;ListNode node = newHead;while (node.next != null) {node = node.next;}node.next = head;return newHead;}
86. 分隔链表
public ListNode partition(ListNode head, int x) {if (head == null) {return head;}ListNode leftDummy = new ListNode(-1);ListNode left = leftDummy;ListNode rightDummy = new ListNode(-1);ListNode right = rightDummy;ListNode current = head;while (current != null) {if (current.val < x) {left.next = current;left = left.next;} else {right.next = current;right = right.next;}current = current.next;}right.next = null;left.next = rightDummy.next;return leftDummy.next;}
143. 重排链表
public void reorderList(ListNode head) {if (head == null) {return;}ListNode mid = middleNode(head);ListNode l1 = head;ListNode l2 = mid.next;mid.next = null;l2 = reverseListNode(l2);mergeListNode(l1, l2);}private ListNode middleNode(ListNode head) {ListNode slow = head, fast = head;while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;}return slow;}private ListNode reverseListNode(ListNode node) {ListNode current = node, pre = null, next = null;while (current != null) {next = current.next;current.next = pre;pre = current;current = next;}return pre;}private void mergeListNode(ListNode l1, ListNode l2) {ListNode l1Tmp;ListNode l2Tmp;while (l1 != null && l2 != null) {l1Tmp = l1.next;l2Tmp = l2.next;l1.next = l2;l1 = l1Tmp;l2.next = l1;l2 = l2Tmp;}}
四、栈和队列
20. 有效的括号
public boolean isValid(String s) {Stack<Character> stack = new Stack<>();char[] array = s.toCharArray();for (char c : array) {if (stack.isEmpty()) {stack.add(c);} else if (check(stack.peek(), c)) {stack.pop();} else {stack.add(c);}}return stack.isEmpty();}private boolean check(char c1, char c2) {return (c1 == '(' && c2 == ')') || (c1 == '{' && c2 == '}') || (c1 == '[' && c2 == ']');}
225. 用队列实现栈
class MyStack {private Queue<Integer> q1;private Queue<Integer> q2;private int top;public MyStack() {this.q1 = new LinkedList<>();this.q2 = new LinkedList<>();}public void push(int x) {top = x;q1.offer(x);}public int pop() {while (q1.size() > 1) {top = q1.poll();q2.offer(top);}int result = q1.poll();Queue<Integer> tmp = q1;q1 = q2;q2 = tmp;return result;}public int top() {return top;}public boolean empty() {return q1.isEmpty();}
}
155. 最小栈
class MinStack {private Stack<Integer> stack;private Stack<Integer> minStack;public MinStack() {this.stack = new Stack<>();this.minStack = new Stack<>();}public void push(int val) {stack.add(val);if (!minStack.isEmpty() && val > minStack.peek()) {minStack.add(minStack.peek());} else {minStack.add(val);}}public void pop() {stack.pop();minStack.pop();}public int top() {return stack.peek();}public int getMin() {return minStack.peek();}
}
五、堆
215. 数组中的第K个最大元素
思路:小顶堆
public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> queue = new PriorityQueue<>();for (int num : nums) {if (queue.size() < k) {queue.offer(num);} else if (queue.peek() < num) {queue.poll();queue.offer(num);}}return queue.peek();}
六、哈希表
3. 无重复字符的最长子串
public int lengthOfLongestSubstring(String s) {int i = 0, j = 0, result = 0, n = s.length();Set<Character> set = new HashSet<>();while (i < n && j < n) {if (!set.contains(s.charAt(i))) {set.add(s.charAt(i++));result = Math.max(result, i - j);} else {set.remove(s.charAt(j++));}}return result;}
128. 最长连续序列
public int longestConsecutive(int[] nums) {Set<Integer> numSet = new HashSet<>();for (int num : nums) {numSet.add(num);}int result = 0, seqLen = 0;for (int num : numSet) {if (!numSet.contains(num - 1)) {seqLen = 1;while (numSet.contains(++num)) {seqLen++;}result = Math.max(seqLen, result);}}return result;}
1. 两数之和
public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i < nums.length; ++i) {int temp = target - nums[i];if (map.containsKey(temp)) {return new int[]{i, map.get(temp)};}map.put(nums[i], i);}return new int[]{};}
169. 多数元素
public int majorityElement(int[] nums) {Map<Integer, Integer> countMap = count(nums);Map.Entry<Integer, Integer> map = null;for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {if (map == null || entry.getValue() > map.getValue()) {map = entry;}}return map.getKey();}private Map<Integer, Integer> count(int[] nums) {Map<Integer, Integer> result = new HashMap<>();for (int num : nums) {result.put(num, result.getOrDefault(num, 0) + 1);}return result;}
242. 有效的字母异位词
public boolean isAnagram(String s, String t) {if (s.length() != t.length()) {return false;}int[] array = new int[26];for (int i = 0; i < s.length(); ++i) {array[s.charAt(i) - 'a']++;array[t.charAt(i) - 'a']--;}for (int i : array) {if (i != 0) {return false;}}return true;}
49. 字母异位词分组
public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> map = new HashMap<>();for (String str : strs) {char[] array = str.toCharArray();Arrays.sort(array);String s = String.valueOf(array);if (map.containsKey(s)) {map.get(s).add(str);} else {List<String> tmpList = new ArrayList<>();tmpList.add(str);map.put(s, tmpList);}}return new ArrayList<>(map.values());}
594. 最长和谐子序列
public int findLHS(int[] nums) {Map<Integer, Integer> countMap = count(nums);int result = 0;for (int key : countMap.keySet()) {if (countMap.containsKey(key + 1)) {result = Math.max(result, countMap.get(key) + countMap.get(key + 1));}}return result;}private Map<Integer, Integer> count(int[] nums) {Map<Integer, Integer> result = new HashMap<>();for (int num : nums) {result.put(num, result.getOrDefault(num, 0) + 1);}return result;}
七、滑动窗口
209. 长度最小的子数组
public int minSubArrayLen(int target, int[] nums) {int start = 0, end = 0, sum = 0, n = nums.length, result = Integer.MAX_VALUE;while (end < n) {sum += nums[end];while (sum >= target) {result = Math.min(end - start + 1, result);sum -= nums[start];start++;}end++;}return result == Integer.MAX_VALUE ? 0 : result;}
八、LRU Cache
146. LRU 缓存
思路:哈希表+双向链表
class LRUCache {private int capacity;private Map<Integer, Integer> cache;private LinkedList<Integer> keys;public LRUCache(int capacity) {this.capacity = capacity;this.cache = new HashMap<>();this.keys = new LinkedList<>();}public int get(int key) {if (!cache.containsKey(key)) {return -1;}int result = cache.get(key);put(key, result);return result;}public void put(int key, int value) {if (cache.containsKey(key)) {keys.remove((Integer) key);} else if (keys.size() >= capacity) {Integer old = keys.removeFirst();cache.remove(old);}cache.put(key, value);keys.addLast(key);}
}
九、二叉树
常用解法及操作:
- 二叉树前中后序遍历
- 二叉树层序遍历
完全二叉树的定义:
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第h层,则该层包含1~ 2h个节点
二叉搜索树的定义:
- 节点的左子树只包含小于当前节点的数
- 节点的右子树只包含大于当前节点的数
- 所有左子树和右子树自身必须也是二叉搜索树
104. 二叉树的最大深度
public int maxDepth(TreeNode root) {if(root==null){return 0;}return Math.max(maxDepth(root.left),maxDepth(root.right))+1;}
100. 相同的树
public boolean isSameTree(TreeNode p, TreeNode q) {if (p == null) {return q == null;}return q != null && p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}
226. 翻转二叉树
public TreeNode invertTree(TreeNode root) {if (root == null) {return root;}TreeNode left = invertTree(root.left);TreeNode right = invertTree(root.right);root.left = right;root.right = left;return root;}
101. 对称二叉树
public boolean isSymmetric(TreeNode root) {if (root == null) {return true;}return helper(root.left, root.right);}private boolean helper(TreeNode left, TreeNode right) {if (left == null && right == null) {return true;}if (left == null || right == null) {return false;}return left.val == right.val && helper(left.right, right.left) && helper(left.left, right.right);}
114. 二叉树展开为链表
public void flatten(TreeNode root) {if (root == null) {return;}List<TreeNode> nodeList = new ArrayList<>();inorder(root, nodeList);for (int i = 1; i < nodeList.size(); ++i) {TreeNode last = nodeList.get(i - 1);TreeNode current = nodeList.get(i);last.left = null;last.right = current;}}private void inorder(TreeNode node, List<TreeNode> nodeList) {if (node == null) {return;}nodeList.add(node);inorder(node.left, nodeList);inorder(node.right, nodeList);}
112. 路径总和
public boolean hasPathSum(TreeNode root, int targetSum) {if (root == null) {return false;}if (root.left == null && root.right == null) {return root.val == targetSum;}return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);}
129. 求根节点到叶节点数字之和
public int sumNumbers(TreeNode root) {return helper(root, 0);}private int helper(TreeNode node, int preSum) {if (node == null) {return preSum;}int sum = preSum * 10 + node.val;if (node.left == null && node.right == null) {return sum;}return helper(node.left, sum) + helper(node.right, sum);}
124. 二叉树中的最大路径和
Integer max = Integer.MIN_VALUE;public int maxPathSum(TreeNode root) {helper(root);return max;}private int helper(TreeNode node) {if (node == null) {return 0;}int left = helper(node.left);int right = helper(node.right);max = Math.max(max, node.val + left + right);return Math.max(0, node.val + Math.max(left, right));}
222. 完全二叉树的节点个数
public int countNodes(TreeNode root) {if (root == null) {return 0;}return countNodes(root.left) + countNodes(root.right) + 1;}
236. 二叉树的最近公共祖先
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;} else if (right == null) {return left;} else {return root;}}
117. 填充每个节点的下一个右侧节点指针 II
public Node connect(Node root) {if (root == null) {return null;}LinkedList<Node> tmpList = new LinkedList<>();tmpList.add(root);while (!tmpList.isEmpty()) {int n = tmpList.size();Node last = null;for (int i = 0; i < n; ++i) {Node node = tmpList.poll();if (node.left != null) {tmpList.add(node.left);}if (node.right != null) {tmpList.add(node.right);}if (last != null) {last.next = node;}last = node;}}return root;}
102. 二叉树的层序遍历
public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (root == null) {return result;}LinkedList<TreeNode> tmpList = new LinkedList<>();tmpList.add(root);while (!tmpList.isEmpty()) {int n = tmpList.size();List<Integer> level = new ArrayList<>();for (int i = 0; i < n; ++i) {TreeNode node = tmpList.poll();level.add(node.val);if (node.left != null) {tmpList.add(node.left);}if (node.right != null) {tmpList.add(node.right);}}result.add(level);}return result;}
199. 二叉树的右视图
思路:二叉树层次遍历取最后一个
public List<Integer> rightSideView(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) {return result;}LinkedList<TreeNode> tmpList = new LinkedList<>();tmpList.add(root);while (!tmpList.isEmpty()) {int n = tmpList.size();for (int i = 0; i < n; ++i) {TreeNode node = tmpList.poll();if (node.left != null) {tmpList.add(node.left);}if (node.right != null) {tmpList.add(node.right);}if (i == n - 1) {result.add(node.val);}}}return result;}
637. 二叉树的层平均值
public List<Double> averageOfLevels(TreeNode root) {List<Double> result = new ArrayList<>();if (root == null) {return result;}LinkedList<TreeNode> tmpList = new LinkedList<>();tmpList.add(root);while (!tmpList.isEmpty()) {double sum = 0;int n = tmpList.size();for (int i = 0; i < n; ++i) {TreeNode node = tmpList.poll();sum += node.val;if (node.left != null) {tmpList.add(node.left);}if (node.right != null) {tmpList.add(node.right);}}result.add(sum / n);}return result;}
103. 二叉树的锯齿形层序遍历
思路:二叉树层次遍历,对应层翻转
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (root == null) {return result;}LinkedList<TreeNode> tmpList = new LinkedList<>();tmpList.add(root);while (!tmpList.isEmpty()) {int n = tmpList.size();List<Integer> levelList = new ArrayList<>();for (int i = 0; i < n; ++i) {TreeNode node = tmpList.poll();if (node.left != null) {tmpList.add(node.left);}if (node.right != null) {tmpList.add(node.right);}levelList.add(node.val);}if (result.size() % 2 == 1) {Collections.reverse(levelList);}result.add(levelList);}return result;}
98. 验证二叉搜索树
double last = -Double.MAX_VALUE;public boolean isValidBST(TreeNode root) {if (root == null) {return true;}if (isValidBST(root.left)) {if (last < root.val) {last = root.val;return isValidBST(root.right);}}return false;}
230. 二叉搜索树中第K小的元素
List<Integer> tmpList = new ArrayList<>();public int kthSmallest(TreeNode root, int k) {helper(root);return tmpList.get(k - 1);}private void helper(TreeNode root) {if (root == null) {return;}helper(root.left);tmpList.add(root.val);helper(root.right);}
530. 二叉搜索树的最小绝对差
int pre = -1;int result = Integer.MAX_VALUE;public int getMinimumDifference(TreeNode root) {helper(root);return result;}private void helper(TreeNode node) {if (node == null) {return;}helper(node.left);if (pre == -1) {pre = node.val;} else {result = Math.min(result, node.val - pre);pre = node.val;}helper(node.right);}
173. 二叉搜索树迭代器
class BSTIterator {private int index;private List<Integer> nodeValueList;public BSTIterator(TreeNode root) {this.index = 0;this.nodeValueList = new ArrayList<>();inorder(root, nodeValueList);}public int next() {return nodeValueList.get(index++);}public boolean hasNext() {return index < nodeValueList.size();}private void inorder(TreeNode node, List<Integer> tmpList) {if (node == null) {return;}inorder(node.left, tmpList);tmpList.add(node.val);inorder(node.right, tmpList);}
}
十、图
200. 岛屿数量
思路:
public int numIslands(char[][] grid) {int m = grid.length, n = grid[0].length, count = 0;for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (grid[i][j] == '1') {count++;dfs(i, j, grid);}}}return count;}private void dfs(int i, int j, char[][] grid) {int m = grid.length, n = grid[0].length;if (i < 0 || j < 0 || i >= m || j >= n || grid[i][j] == '0') {return;}grid[i][j] = '0';dfs(i - 1, j, grid);dfs(i + 1, j, grid);dfs(i, j - 1, grid);dfs(i, j + 1, grid);}
十一、递归
递归模版代码:
public void recur(int level, int param) {//terminator(递归终止条件)if (level > MAX_LEVEL) {//process result return;}//process current logic(处理当前层逻辑)process(level, param);//drill down(下探到下一层)recur(level + 1, newParam);//restore current status(清理当前层)
}
17. 电话号码的字母组合
Map<Character, String> phone = new HashMap<Character, String>() {{put('2', "abc");put('3', "def");put('4', "ghi");put('5', "jkl");put('6', "mno");put('7', "pqrs");put('8', "tuv");put('9', "wxyz");}};List<String> result = new ArrayList<>();public List<String> letterCombinations(String digits) {if (digits.length() == 0) {return result;}helper(0, digits, "");return result;}private void helper(int depth, String digits, String currentStr) {if (depth == digits.length()) {result.add(currentStr);return;}String latters = phone.get(digits.charAt(depth));for (int i = 0; i < latters.length(); ++i) {helper(depth + 1, digits, currentStr + latters.charAt(i));}}
77. 组合
List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> combine(int n, int k) {helper(1, new ArrayList<>(), n, k);return result;}private void helper(int depth, List<Integer> tmpList, int n, int k) {if (tmpList.size() == k) {result.add(new ArrayList<>(tmpList));return;}for (int i = depth; i <= n; ++i) {tmpList.add(i);helper(i + 1, tmpList, n, k);tmpList.remove(tmpList.size() - 1);}}
46. 全排列
List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> permute(int[] nums) {int[] visited = new int[nums.length];helper(new ArrayList<>(), visited, nums);return result;}private void helper(List<Integer> tmpList, int[] visited, int[] nums) {if (tmpList.size() == nums.length) {result.add(new ArrayList<>(tmpList));return;}for (int i = 0; i < nums.length; ++i) {if (visited[i] == 1) {continue;}visited[i] = 1;tmpList.add(nums[i]);helper(tmpList, visited, nums);visited[i] = 0;tmpList.remove(tmpList.size() - 1);}}
39. 组合总和
List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> combinationSum(int[] candidates, int target) {helper(0, new ArrayList<>(), candidates, target);return result;}private void helper(int depth, List<Integer> tmpList, int[] candidates, int target) {if (target < 0) {return;}if (target == 0) {result.add(new ArrayList<>(tmpList));return;}for (int i = depth; i < candidates.length; ++i) {tmpList.add(candidates[i]);helper(i, tmpList, candidates, target - candidates[i]);tmpList.remove(tmpList.size() - 1);}}
22. 括号生成
List<String> result = new ArrayList<>();public List<String> generateParenthesis(int n) {helper(0, 0, "", n);return result;}private void helper(int left, int right, String currentStr, int n) {if (left == n && right == n) {result.add(currentStr);return;}if (left < n) {helper(left + 1, right, currentStr + "(", n);}if (right < left) {helper(left, right + 1, currentStr + ")", n);}}
十二、贪心算法
55. 跳跃游戏
public boolean canJump(int[] nums) {int n = nums.length;if (n <= 1) {return true;}int step = 0;for (int i = 0; i < nums.length - 1; ++i) {step = Math.max(step, nums[i]);if (step + i >= nums.length - 1) {return true;}if (step == 0) {return false;}step--;}return false;}
45. 跳跃游戏 II
public int jump(int[] nums) {int step = 0, end = 0, maxFar = 0;for (int i = 0; i < nums.length - 1; ++i) {maxFar = Math.max(maxFar, i + nums[i]);if (end == i) {end = maxFar;step++;}}return step;}
455. 分发饼干
思路:排序+双指针+贪心
public int findContentChildren(int[] g, int[] s) {Arrays.sort(g);Arrays.sort(s);int m = g.length, n = s.length, result = 0;for (int i = 0, j = 0; i < m && j < n; ++i, ++j) {while (j < n && g[i] > s[j]) {j++;}if (j < n) {result++;}}return result;}
十三、二分查找
35. 搜索插入位置
public int searchInsert(int[] nums, int target) {int low = 0, high = nums.length - 1, mid;while (low <= high) {mid = low + (high - low) / 2;if (nums[mid] > target) {high = mid - 1;} else if (nums[mid] < target) {low = mid + 1;} else {return mid;}}return low;}
33. 搜索旋转排序数组
public int search(int[] nums, int target) {int low = 0, high = nums.length - 1;while (low <= high) {int mid = low + (high - low) / 2;if (nums[mid] == target) {return mid;}if (nums[mid] >= nums[low]) {if (target >= nums[low] && target < nums[mid]) {high = mid - 1;} else {low = mid + 1;}} else {if (target > nums[mid] && target <= nums[high]) {low = mid + 1;} else {high = mid - 1;}}}return -1;}
852. 山脉数组的峰顶索引
public int peakIndexInMountainArray(int[] arr) {int low = 1, high = arr.length - 2, result = 0;while (low <= high) {int mid = low + (high - low) / 2;if (arr[mid] > arr[mid + 1]) {result = mid;high = mid - 1;} else {low = mid + 1;}}return result;}
540. 有序数组中的单一元素
public int singleNonDuplicate(int[] nums) {int left = 0, right = nums.length - 1;while (left < right) {int mid = (left + right) / 2;if (mid % 2 == 0) {if (nums[mid] == nums[mid + 1]) {left = mid + 1;} else {right = mid;}} else {if (nums[mid] == nums[mid - 1]) {left = mid + 1;} else {right = mid;}}}return nums[right];}
十四、一维动态规划
70. 爬楼梯
public int climbStairs(int n) {if (n <= 2) {return n;}int[] dp = new int[n + 1];dp[1] = 1;dp[2] = 2;for (int i = 3; i <= n; ++i) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
121. 买卖股票的最佳时机
public int maxProfit(int[] prices) {int min = Integer.MAX_VALUE;int max = 0;for (int price : prices) {min = Math.min(min, price);max = Math.max(max, price - min);}return max;}
122. 买卖股票的最佳时机 II
public int maxProfit(int[] prices) {int result = 0;for (int i = 1; i < prices.length; ++i) {if (prices[i] - prices[i - 1] > 0) {result += prices[i] - prices[i - 1];}}return result;}
53. 最大子数组和
public int maxSubArray(int[] nums) {int[] dp = new int[nums.length];int result = Integer.MIN_VALUE;for (int i = 0; i < nums.length; ++i) {if (i >= 1 && dp[i - 1] > 0) {dp[i] = dp[i - 1] + nums[i];} else {dp[i] = nums[i];}result = Math.max(dp[i], result);}return result;}
152. 乘积最大子数组
public int maxProduct(int[] nums) {int max = Integer.MIN_VALUE, imax = 1, imin = 1;for (int i = 0; i < nums.length; ++i) {if (nums[i] < 0) {int tmp = imax;imax = imin;imin = tmp;}imax = Math.max(imax * nums[i], nums[i]);imin = Math.min(imin * nums[i], nums[i]);max = Math.max(max, imax);}return max;}
300. 最长递增子序列
public int lengthOfLIS(int[] nums) {if (nums.length == 0) {return 0;}int[] dp = new int[nums.length];int result = 0;for (int i = 0; i < nums.length; ++i) {dp[i] = 1;for (int j = 0; j < i; ++j) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[j] + 1, dp[i]);}}result = Math.max(result, dp[i]);}return result;}
198. 打家劫舍
public int rob(int[] nums) {if (nums == null || nums.length == 0) {return 0;}if (nums.length == 1) {return nums[0];}int[] dp = new int[nums.length];dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1]);for (int i = 2; i < nums.length; ++i) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[nums.length - 1];}
139. 单词拆分
public boolean wordBreak(String s, List<String> wordDict) {Set<String> set = new HashSet<>(wordDict);boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for (int i = 1; i <= s.length(); ++i) {for (int j = 0; j < i; ++j) {if (dp[j] && set.contains(s.substring(j, i))) {dp[i] = true;break;}}}return dp[s.length()];}
322. 零钱兑换
public int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];for (int i = 1; i <= amount; ++i) {int tmp = amount + 1;for (int coin : coins) {if (i >= coin) {tmp = Math.min(tmp, dp[i - coin] + 1);}}dp[i] = tmp;}return dp[amount] == amount + 1 ? -1 : dp[amount];}
十五、二维动态规划
120. 三角形最小路径和
public int minimumTotal(List<List<Integer>> triangle) {int n = triangle.size();int[][] dp = new int[n][n];dp[0][0] = triangle.get(0).get(0);for (int i = 1; i < triangle.size(); ++i) {dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0);for (int j = 1; j < i; ++j) {dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j);}dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i);}int minTotal = dp[n - 1][0];for (int i = 1; i < n; ++i) {minTotal = Math.min(minTotal, dp[n - 1][i]);}return minTotal;}
64. 最小路径和
public int minPathSum(int[][] grid) {for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (i == 0 && j == 0) {continue;} else if (i == 0) {grid[0][j] = grid[0][j - 1] + grid[i][j];} else if (j == 0) {grid[i][0] = grid[i - 1][0] + grid[i][j];} else {grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j];}}}return grid[grid.length - 1][grid[0].length - 1];}
63. 不同路径 II
public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;if (m == 0 || obstacleGrid[0][0] == 1) {return 0;}obstacleGrid[0][0] = 1;int n = obstacleGrid[0].length;for (int i = 1; i < m; ++i) {obstacleGrid[i][0] = obstacleGrid[i - 1][0] == 1 && obstacleGrid[i][0] == 0 ? 1 : 0;}for (int j = 1; j < n; ++j) {obstacleGrid[0][j] = obstacleGrid[0][j - 1] == 1 && obstacleGrid[0][j] == 0 ? 1 : 0;}for (int i = 1; i < m; ++i) {for (int j = 1; j < n; ++j) {if (obstacleGrid[i][j] == 1) {obstacleGrid[i][j] = 0;} else {obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1];}}}return obstacleGrid[m - 1][n - 1];}
5. 最长回文子串
public String longestPalindrome(String s) {int n = s.length();String result = "";boolean[][] dp = new boolean[n][n];for (int i = n - 1; i >= 0; --i) {for (int j = i; j < n; ++j) {if (j == i) {dp[i][j] = true;} else if (j - i == 1 && s.charAt(i) == s.charAt(j)) {dp[i][j] = true;} else if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {dp[i][j] = true;}if (dp[i][j] && result.length() < j - i + 1) {result = s.substring(i, j + 1);}}}return result;}
97. 交错字符串
public boolean isInterleave(String s1, String s2, String s3) {int n = s1.length(), m = s2.length(), t = s3.length();if (n + m != t) {return false;}boolean[][] dp = new boolean[n + 1][m + 1];dp[0][0] = true;for (int i = 0; i <= n; ++i) {for (int j = 0; j <= m; ++j) {int p = i + j - 1;if (i > 0) {dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p));}if (j > 0) {dp[i][j] = dp[i][j] || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p));}}}return dp[n][m];}
72. 编辑距离
public int minDistance(String word1, String word2) {int[][] dp = new int[word1.length() + 1][word2.length() + 1];for (int i = 1; i < word1.length() + 1; ++i) {dp[i][0] = i;}for (int j = 1; j < word2.length() + 1; ++j) {dp[0][j] = j;}for (int i = 1; i < word1.length() + 1; ++i) {for (int j = 1; j < word2.length() + 1; ++j) {if (word1.charAt(i - 1) == word2.charAt(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 - 1][j]), dp[i][j - 1]) + 1;}}}return dp[word1.length()][word2.length()];}
221. 最大正方形
public int maximalSquare(char[][] matrix) {int maxSide = 0;if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {return maxSide;}int m = matrix.length, n = matrix[0].length;int[][] dp = new int[m][n];for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {if (matrix[i][j] == '1') {if (i == 0 || j == 0) {dp[i][j] = 1;} else {dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i - 1][j - 1]), dp[i][j - 1]) + 1;}maxSide = Math.max(maxSide, dp[i][j]);}}}return maxSide * maxSide;}
十六、排序算法
冒泡排序:
public void bubbleSort(int[] nums, int n) {for (int i = 0; i < n; ++i) {boolean flag = false;for (int j = 0; j < n - i - 1; ++j) {if (nums[j + 1] < nums[j]) {int tmp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = tmp;flag = true;}}if (!flag) {break;}}}
快速排序:
public void quickSort(int[] nums, int p, int r) {if (p >= r) {return;}int q = partition(nums, p, r);quickSort(nums, p, q - 1);quickSort(nums, q + 1, r);}private int partition(int[] nums, int p, int r) {int pivot = nums[r];int i = p;for (int j = p; j < r; ++j) {if (nums[j] < pivot) {if (i != j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}i++;}}nums[r] = nums[i];nums[i] = pivot;return i;}