一、数组
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--;
}
}
4. 最长公共前缀
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;
}
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;
}