class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{i, map.get(target - nums[i])};
}
map.put(nums[i], i);
}
return new int[]{};
}
}
Map+排序
class Solution {
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的方法,不能用toString
String key = new String(array);
List<String> list = map.getOrDefault(key, new ArrayList<>());
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int res = 0;
for (int num : nums) {
// set中不包含num - 1时统计序列长度
if (!set.contains(num - 1)) {
int curNum = num;
int curRes = 1;
while (set.contains(curNum + 1)) {
curRes++;
curNum++;
}
res = Math.max(res, curRes);
}
}
return res;
}
}
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j++] = tmp;
}
}
}
}
class Solution {
public int maxArea(int[] height) {
int res = 0;
int left = 0, right = height.length - 1;
while (left <= right) {
int weight = right - left;
int curRes = 0;
if (height[right] > height[left]) {
curRes = height[left] * weight;
left++;
} else {
curRes = height[right] * weight;
right--;
}
res = Math.max(res, curRes);
}
return res;
}
}
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
// 保证i没被考虑过,只使用每个值的第一个位置
if (i > 0 && nums[i] == nums[i - 1]) continue;
// 优化,最小的三个数大于0则停止循环
if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break;
// 优化,与最后两个数相加小于0则可以进入下一个循环
if (nums[i] + nums[n - 1] + nums[n - 2] < 0) continue;
int l = i + 1, r = n - 1;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (sum == 0) {
List<Integer> list = Arrays.asList(nums[i], nums[l], nums[r]);
res.add(list);
while (l < r && nums[l] == nums[l + 1]) ++l; // 跳过重复的元素
while (l < r && nums[r] == nums[r - 1]) --r; // 跳过重复的元素
++l; --r;
} else if (sum < 0) {
l++;
} else {
r--;
}
}
}
return res;
}
}
盛最多水的容器 接雨水_哔哩哔哩_bilibili
前缀最大值数组+后缀最大值数组
class Solution {
public int trap(int[] height) {
int n = height.length;
int[] pre_arr = new int[n];
int[] suf_arr = new int[n];
pre_arr[0] = height[0];
suf_arr[n - 1] = height[n - 1];
int res = 0;
for (int i = 1; i < n; i++) {
pre_arr[i] = Math.max(height[i], pre_arr[i - 1]);
}
for (int j = n - 2; j >= 0; j--) {
suf_arr[j] = Math.max(height[j], suf_arr[j + 1]);
}
for (int i = 0; i < n; i++) {
res += Math.min(pre_arr[i], suf_arr[i]) - height[i];
}
return res;
}
}
空间优化
class Solution {
public int trap(int[] height) {
int n = height.length;
int left = 0, right = n - 1;
int pre_max = 0, suf_max = 0;
int res = 0;
while (left < right) {
pre_max = Math.max(pre_max, height[left]);
suf_max = Math.max(suf_max, height[right]);
if (pre_max < suf_max) {
res += pre_max - height[left];
left++;
} else {
res += suf_max - height[right];
right--;
}
}
return res;
}
}
遍历右端点,缩减左端点
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int sum = 0;
int left = 0;
int res = n + 1;
// 遍历右端点
for (int i = 0; i < n; i++) {
sum += nums[i];
while (sum - nums[left] >= target) {
sum -= nums[left++];
}
// 这里加一层判断的原因是刚开始遍历时可能sum
if (sum >= target) {
res = Math.min(res, i - left + 1);
}
}
return res > n ? 0 : res;
}
}
遍历右端点,缩减左端点
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
if (k <= 1) return 0;
int left = 0, n = nums.length;
int res = 0, prod = 1;
for (int i = 0; i < n; i++) {
prod *= nums[i];
while (prod >= k) {
prod /= nums[left];
left++;
}
// 以i为右端点的子数组数目就是长度
res += i - left + 1;
}
return res;
}
}
滑动窗口【基础算法精讲 03】_哔哩哔哩_bilibili
class Solution {
public int lengthOfLongestSubstring(String s) {
char[] arr = s.toCharArray();
int n = s.length();
int res = 0;
int left = 0;
// map记录字符出现的次数
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < n; i++) {
map.put(arr[i], map.getOrDefault(arr[i], 0) + 1);
while (map.get(arr[i]) > 1) {
map.put(arr[left], map.get(arr[left]) - 1);
left++;
}
res = Math.max(res, i - left + 1);
}
return res;
}
}
// 优化
class Solution {
public int lengthOfLongestSubstring(String s) {
char[] arr = s.toCharArray();
int n = s.length();
int res = 0;
int left = 0;
// map记录字符最后出现的位置
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < n; i++) {
if (map.containsKey(arr[i])) {
left = Math.max(left, map.get(arr[i]) + 1);
}
map.put(arr[i], i);
res = Math.max(res, i - left + 1);
}
return res;
}
}
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sLen = s.length(), pLen = p.length();
if (sLen < pLen) return new ArrayList<Integer>();
List<Integer> res = new ArrayList<>();
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)) res.add(0);
// 遍历右端点
for (int i = pLen; i < sLen; i++) {
sCount[s.charAt(i) - 'a']++;
// 移动左端点
sCount[s.charAt(i - pLen) - 'a']--;
if (Arrays.equals(pCount, sCount)) {
res.add(i - pLen + 1);
}
}
return res;
}
}
前缀和
class Solution {
public int subarraySum(int[] nums, int k) {
int res = 0;
int pre = 0;
// map中记录前缀和的个数
Map<Integer, Integer> map = new HashMap<>();
// 初始化map,存在前缀和刚好为k的情况
map.put(0, 1);
for (int num : nums) {
pre += num;
if (map.containsKey(pre - k)) {
// 结果加上前缀和为pre-k的个数
res += map.get(pre - k);
}
map.put(pre, map.getOrDefault(pre, 0) + 1);
}
return res;
}
}
单调队列 滑动窗口最大值【基础算法精讲 27】_哔哩哔哩_bilibili
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deq = new LinkedList<>();
int n = nums.length;
int[] res = new int[n - k + 1];
for (int i = 0; i < n; i++) {
// 1 入
while (!deq.isEmpty() && nums[deq.getLast()] <= nums[i]) {
deq.removeLast();
}
deq.addLast(i);
// 2 出
if (i - deq.getFirst() + 1 > k) { // 队首已经离开窗口
deq.removeFirst();
}
// 3 添加结果
if (i + 1 >= k) {
res[i - k + 1] = nums[deq.getFirst()];
}
}
return res;
}
}
题目:给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
class Solution {
public String minWindow(String S, String T) {
char[] s = S.toCharArray();
char[] t = T.toCharArray();
int m = s.length;
int ansLeft = -1;
int ansRight = m;
int left = 0;
int[] cntS = new int[128]; // s 子串字母的出现次数
int[] cntT = new int[128]; // t 中字母的出现次数
for (char c : t) {
cntT[c]++;
}
for (int right = 0; right < m; right++) { // 移动子串右端点
cntS[s[right]]++; // 右端点字母移入子串
while (isCovered(cntS, cntT)) { // 涵盖
if (right - left < ansRight - ansLeft) { // 找到更短的子串
ansLeft = left; // 记录此时的左右端点
ansRight = right;
}
cntS[s[left++]]--; // 左端点字母移出子串
}
}
return ansLeft < 0 ? "" : S.substring(ansLeft, ansRight + 1);
}
private boolean isCovered(int[] cntS, int[] cntT) {
for (int i = 'A'; i <= 'Z'; i++) {
if (cntS[i] < cntT[i]) {
return false;
}
}
for (int i = 'a'; i <= 'z'; i++) {
if (cntS[i] < cntT[i]) {
return false;
}
}
return true;
}
}
动态规划,记录当前最大和
class Solution {
public int maxSubArray(int[] nums) {
int pre = 0, res = nums[0];
for (int num : nums) {
pre = Math.max(pre + num, num);
res = Math.max(res, pre);
}
return res;
}
}
https://leetcode.cn/problems/merge-intervals/description/
思路:先排序,再合并
class Solution {
public int[][] merge(int[][] intervals) {
if (intervals.length == 0) {
return new int[0][2];
}
Arrays.sort(intervals, new Comparator<int[]>() {
public int compare(int[] interval1, int[] interval2) {
return interval1[0] - interval2[0];
}
});
List<int[]> merged = new ArrayList<>();
for (int i = 0; i < intervals.length; i++) {
int L = intervals[i][0], R = intervals[i][1];
if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) {
merged.add(new int[]{L, R});
} else {
merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R);
}
}
return merged.toArray(new int[merged.size()][]);
}
}
3次翻转
class Solution {
public void rotate(int[] nums, int k) {
k = k % nums.length;
reverse(nums, 0, nums.length - k - 1);
reverse(nums, nums.length - k, nums.length - 1);
reverse(nums, 0, nums.length - 1);
}
public void reverse(int[] nums, int l, int r) {
while (l < r) {
int tmp = nums[l];
nums[l++] = nums[r];
nums[r--] = tmp;
}
}
}
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
// 计算左侧乘积
res[0] = 1;
for (int i = 1; i < n; i++) {
res[i] = res[i - 1] * nums[i - 1];
}
// 合并右侧乘积
int R = 1;
for (int i = n - 1; i >= 0; i--) {
res[i] = res[i] * R;
R *= nums[i];
}
return res;
}
}
class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
// 把小于0的数变为n+1
for (int i = 0; i < n; i++) {
if (nums[i] <= 0) {
nums[i] = n + 1;
}
}
// 原地哈希,把不大于n的数对应位置置为负
for (int i = 0; i < n; i++) {
int x = Math.abs(nums[i]);
if (x <= n) {
nums[x - 1] = -Math.abs(nums[x - 1]);
}
}
// 大于0的位置对应缺少的正数
for (int i = 0; i < n; i++) {
if (nums[i] > 0) {
return i + 1;
}
}
return n + 1;
}
}
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
boolean flagRow0 = false, 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[i][0] = 0;
matrix[0][j] = 0;
}
}
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
if (flagCol0 == true) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
if (flagRow0 == true) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
}
}
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int u = 0, d = matrix.length - 1, l = 0, r = matrix[0].length - 1;
while (true) {
for (int i = l; i <= r; i++) res.add(matrix[u][i]);
if (++u > d) break;
for (int i = u; i <= d; i++) res.add(matrix[i][r]);
if (--r < l) break;
for (int i = r; i >= l; i--) res.add(matrix[d][i]);
if (--d < u) break;
for (int i = d; i >= u; i--) res.add(matrix[i][l]);
if (++l > r) break;
}
return res;
}
}
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 水平翻转
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n; j++) {
int tmp = matrix[i][j];
matrix[i][j] = matrix[n - 1 - i][j];
matrix[n - 1 - i][j] = tmp;
}
}
// 主对角线翻转
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}
}
}
从右上角开始搜索
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length, n = matrix[0].length;
int i = 0, j = n - 1;
while (i < m && j >= 0) {
if (matrix[i][j] == target) {
return true;
} else if (matrix[i][j] > target) {
j--;
} else {
i++;
}
}
return false;
}
}
public class Solution {
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 ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
三指针法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
快慢指针
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) return false;
ListNode p = head, q = head;
while (q.next != null && q.next.next != null) {
p = p.next;
q = q.next.next;
}
q = head;
p = reverse(p.next);
while (p != null) {
if (p.val != q.val) {
return false;
}
p = p.next;
q = q.next;
}
return true;
}
public ListNode reverse(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
}
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) return null;
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
}
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
if (list1.val < list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
} else {
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
}
}
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
int tmp = 0;
ListNode head = null, tail = null;
while (l1 != null || l2 != null) {
int x = l1 == null ? 0 : l1.val;
int y = l2 == null ? 0 : l2.val;
int sum = x + y + tmp;
if (head == null) {
head = tail = new ListNode(sum % 10);
} else {
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
tmp = sum / 10;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
if (tmp > 0) {
tail.next = new ListNode(tmp);
}
return head;
}
}
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode p = head, q = head;
for (int i = 0; i < n - 1; i++) {
q = q.next;
}
while (q.next != null) {
p = p.next;
q = q.next;
}
if (p == head) return head.next;
ListNode pre = head;
while (pre.next != p) {
pre = pre.next;
}
pre.next = p.next;
p.next = null;
return head;
}
}
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode q = head.next;
head.next = swapPairs(q.next);
q.next = head;
return q;
}
}
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null) return head;
ListNode p = head;
int len = 0;
while (p != null && len < k) {
p = p.next;
len++;
}
if (len < k) return head;
ListNode nextHead = p;
ListNode pre = null;
ListNode cur = head;
ListNode next = null;
while (cur != nextHead) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
head.next = reverseKGroup(nextHead, k);
return pre;
}
}
哈希存储节点
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return head;
Map<Node, Node> map = new HashMap<>();
Node cur = head;
while (cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while (cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
}
分治
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode tmp = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(tmp);
return mergeTwoList(left, right);
}
public 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;
}
}
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int n = lists.length;
return merge(lists, 0, n - 1);
}
public ListNode merge(ListNode[] lists, int l, int r) {
if (l == r) return lists[l];
if (l > r) return null;
int mid = l + r >> 1;
ListNode left = merge(lists, l, mid);
ListNode right = merge(lists, mid + 1, r);
return mergeTwoList(left, right);
}
public 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;
}
}
}
哈希+双向链表
class LRUCache {
class DLinkedNode {
int key;
int val;
DLinkedNode pre;
DLinkedNode next;
DLinkedNode(){}
DLinkedNode(int key, int val) {
this.key = key;
this.val = val;
}
}
private Map<Integer, DLinkedNode> cache = new HashMap<>();
private int size;
private int capacity;
private DLinkedNode head, tail;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.pre = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) {
return -1;
}
moveToHead(node);
return node.val;
}
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if (node != null) {
node.val = value;
moveToHead(node);
} else {
DLinkedNode newNode = new DLinkedNode(key, value);
cache.put(key, newNode);
addToHead(newNode);
size++;
if (size > capacity) {
removeTail();
cache.remove(tail.key);
size--;
}
}
}
private void addToHead(DLinkedNode node) {
head.next.pre = node;
node.next = head.next;
node.pre = head;
head.next = node;
}
private void moveToHead(DLinkedNode node) {
node.next.pre = node.pre;
node.pre.next = node.next;
addToHead(node);
}
private void removeTail() {
DLinkedNode node = tail.pre;
cache.remove(node.key);
node.pre.next = tail;
tail.pre = node.pre;
}
}
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
inorder(root);
return res;
}
private void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
res.add(root.val);
inorder(root.right);
}
}
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
}
}
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
class Solution {
public boolean isSymmetric(TreeNode root) {
return isSymmetric(root, root);
}
public boolean isSymmetric(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p == null || q == null) return false;
return (p.val == q.val) && isSymmetric(p.left, q.right) &&
isSymmetric(p.right, q.left);
}
}
class Solution {
int res = 0;
public int diameterOfBinaryTree(TreeNode root) {
height(root);
return res;
}
public int height(TreeNode root) {
if (root == null) return 0;
int left = height(root.left);
int right = height(root.right);
res = Math.max(res, left + right);
return Math.max(left, right) + 1;
}
}
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (queue.size() != 0) {
int len = queue.size();
List<Integer> level = new ArrayList();
for (int i = 0; i < len; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
res.add(level);
}
return res;
}
}
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return BST(nums, 0, nums.length - 1);
}
private TreeNode BST(int[] nums, int l, int r) {
if (l == r) return new TreeNode(nums[l]);
if (l > r) return null;
int mid = l + r >> 1;
TreeNode root = new TreeNode(nums[mid]);
root.left = BST(nums, l, mid - 1);
root.right = BST(nums, mid + 1, r);
return root;
}
}
class Solution {
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
TreeNode leftMax = findMax(root.left);
TreeNode rightMin = findMin(root.right);
if (leftMax != null && leftMax.val >= root.val) return false;
if (rightMin != null && rightMin.val <= root.val) return false;
return isValidBST(root.left) && isValidBST(root.right);
}
private TreeNode findMax(TreeNode root) {
if (root == null) return null;
while (root.right != null) root = root.right;
return root;
}
private TreeNode findMin(TreeNode root) {
if (root == null) return null;
while (root.left != null) root = root.left;
return root;
}
}
class Solution {
int count = 0;
int res;
public int kthSmallest(TreeNode root, int k) {
order(root, k);
return res;
}
private void order(TreeNode root, int k) {
if (root == null) return;
order(root.left, k);
count++;
if (count == k) res = root.val;
order(root.right, k);
}
}
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (queue.size() != 0) {
int len = queue.size();
for (int i = 0; i < len; i++) {
TreeNode node = queue.poll();
if (i == len - 1) res.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return res;
}
}
找到左子树最右边的节点,指向右节点
class Solution {
public void flatten(TreeNode root) {
while (root != null) {
if (root.left == null) {
root = root.right;
} else {
TreeNode pre = findRight(root.left);
pre.right = root.right;
root.right = root.left;
root.left = null;
root = root.right;
}
}
}
public TreeNode findRight(TreeNode root) {
if (root == null) return null;
while (root.right != null) {
root = root.right;
}
return root;
}
}
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
for (int i = 0; i < n; i++) {
map.put(inorder[i], i);
}
return buildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
private TreeNode buildTree(int[] preorder, int[] inorder, int pre_left, int pre_right, int in_left, int in_right) {
if (pre_left > pre_right) return null;
TreeNode root = new TreeNode(preorder[pre_left]);
int loc = map.get(preorder[pre_left]);
int left_size = loc - in_left;
root.left = buildTree(preorder, inorder, pre_left + 1, pre_left + left_size, in_left, loc - 1);
root.right = buildTree(preorder, inorder, pre_left + left_size + 1, pre_right, loc + 1, in_right);
return root;
}
}
class Solution {
// 以root为开头和以左右节点为开头
public int pathSum(TreeNode root, int targetSum) {
if (root == null) return 0;
int res = dfs(root, targetSum);
res += pathSum(root.left, targetSum);
res += pathSum(root.right, targetSum);
return res;
}
// 以root为开头的路径和
private int dfs(TreeNode root, long targetSum) {
int res = 0;
if (root == null) return 0;
if (targetSum == root.val) res++;
res += dfs(root.left, targetSum - root.val);
res += dfs(root.right, targetSum - root.val);
return res;
}
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
// 判断左右是否包含p或q
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;
}
}
给每个节点都赋予一个权重
class Solution {
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
public int maxGain(TreeNode root) {
if (root == null) return Integer.MIN_VALUE;
int left = Math.max(maxGain(root.left), 0);
int right = Math.max(maxGain(root.right), 0);
int price = root.val + left + right;
maxSum = Math.max(maxSum, price);
return Math.max(left, right) + root.val;
}
}
class Solution {
public int numIslands(char[][] grid) {
int m = grid.length, n = grid[0].length;
int res = 0;
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;
}
public void dfs(char[][] grid, int r, int c) {
if (!isInArea(grid, r, c)) return;
if (grid[r][c] != '1') return;
if (grid[r][c] == '1') grid[r][c] = '2';
dfs(grid, r + 1, c);
dfs(grid, r - 1, c);
dfs(grid, r, c + 1);
dfs(grid, r, c - 1);
}
private boolean isInArea(char[][] grid, int r, int c) {
return r >= 0 && r < grid.length &&
c >= 0 && c < grid[0].length;
}
}
层序遍历
class Solution {
public int orangesRotting(int[][] grid) {
// 层序遍历
int m = grid.length, n = grid[0].length;
int count = 0; // 记录新鲜橘子的数量
int res = 0;
Queue<int[]> queue = new LinkedList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) count++;
else if (grid[i][j] == 2) {
queue.add(new int[]{i, j});
}
}
}
while (count > 0 && !queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] pos = queue.poll();
int r = pos[0], c = pos[1];
if (r > 0 && grid[r - 1][c] == 1) {
grid[r - 1][c] = 2;
count--;
queue.add(new int[]{r - 1, c});
}
if (r < m - 1 && grid[r + 1][c] == 1) {
grid[r + 1][c] = 2;
count--;
queue.add(new int[]{r + 1, c});
}
if (c > 0 && grid[r][c - 1] == 1) {
grid[r][c - 1] = 2;
count--;
queue.add(new int[]{r, c - 1});
}
if (c < n - 1 && grid[r][c + 1] == 1) {
grid[r][c + 1] = 2;
count--;
queue.add(new int[]{r, c + 1});
}
}
res++;
}
if (count > 0) {
return -1;
} else {
return res;
}
}
}
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] inDgree = new int[numCourses]; // 记录每门课程的入度
// 记录每门课程的后置课程
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < prerequisites.length; i++) {
inDgree[prerequisites[i][0]]++;
map.putIfAbsent(prerequisites[i][1], new ArrayList<>());
map.get(prerequisites[i][1]).add(prerequisites[i][0]);
}
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < inDgree.length; i++) {
if (inDgree[i] == 0) queue.add(i);
}
while (!queue.isEmpty()) {
int course = queue.poll();
numCourses--;
for (int nextCourse : map.getOrDefault(course, new ArrayList<>())) {
inDgree[nextCourse]--;
if (inDgree[nextCourse] == 0) {
queue.add(nextCourse);
}
}
}
return numCourses == 0;
}
}
class Trie {
private Trie[] children;
private boolean isEnd;
public Trie() {
children = new Trie[26];
isEnd = false;
}
public void insert(String word) {
Trie node = this;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
int index = c - 'a';
if (node.children[index] == null) {
node.children[index] = new Trie();
}
node = node.children[index];
}
node.isEnd = true;
}
public boolean search(String word) {
Trie node = searchPrefix(word);
return node != null && node.isEnd == true;
}
public boolean startsWith(String prefix) {
return searchPrefix(prefix) != null;
}
private Trie searchPrefix(String prefix) {
Trie node = this;
for (int i = 0; i < prefix.length(); i++) {
char c = prefix.charAt(i);
int index = c - 'a';
if (node.children[index] == null) {
return null;
}
node = node.children[index];
}
return node;
}
}
visited数组记录访问状态
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int[] visited = new int[7];
public List<List<Integer>> permute(int[] nums) {
backtrack(nums);
return res;
}
private void backtrack(int[] nums) {
if (path.size() == nums.length) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if (visited[i] == 1) continue;
path.add(nums[i]);
visited[i] = 1;
backtrack(nums);
visited[i] = 0;
path.remove(path.size() - 1);
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrack(nums, 0);
return res;
}
public void backtrack(int[] nums, int i) {
res.add(new ArrayList<>(tmp));
for (int j = i; j < nums.length; j++) {
tmp.add(nums[j]);
backtrack(nums, j + 1);
tmp.remove(tmp.size() - 1);
}
}
}
class Solution {
List<String> res = new ArrayList<>();
StringBuilder path = new StringBuilder();
// 双括号法初始化map
HashMap<Character, String> phoneMap = new HashMap<>(){{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
public List<String> letterCombinations(String digits) {
if (digits.length() == 0) return res;
backtrack(digits, 0);
return res;
}
private void backtrack(String digits, int index) {
if (index == digits.length()) {
res.add(path.toString());
return;
}
String str = phoneMap.get(digits.charAt(index));
for (int i = 0; i < str.length(); i++) {
path.append(str.charAt(i));
backtrack(digits, index + 1);
path.deleteCharAt(path.length() - 1);
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backtrack(candidates, target, 0);
return res;
}
private void backtrack(int[] candidates, int target, int start) {
if (target < 0) return;
if (target == 0) {
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; i++) {
path.add(candidates[i]);
backtrack(candidates, target - candidates[i], i);
path.remove(path.size() - 1);
}
}
}
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
backtrack(new StringBuilder(), 0, 0, n);
return res;
}
public void backtrack(StringBuilder builder, int left, int right, int n) {
if (left + right == n * 2) {
res.add(builder.toString());
return;
}
if (left < n) {
builder.append('(');
backtrack(builder, left + 1, right, n);
builder.deleteCharAt(builder.length() - 1);
}
if (right < left) {
builder.append(')');
backtrack(builder, left, right + 1, n);
builder.deleteCharAt(builder.length() - 1);
}
}
}
class Solution {
public boolean exist(char[][] board, String word) {
char[] words = word.toCharArray();
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (dfs(board, words, i, j, 0)) return true;
}
}
return false;
}
public boolean dfs(char[][] board, char[] words, int i, int j, int k) {
if (i < 0 || i >= board.length || j < 0 || j >= board[0].length
|| board[i][j] != words[k]) return false;
if (k == words.length - 1) return true;
board[i][j] = '\0';
boolean res = dfs(board, words, i + 1, j, k + 1) ||
dfs(board, words, i - 1, j, k + 1) ||
dfs(board, words, i, j + 1, k + 1) ||
dfs(board, words, i, j - 1, k + 1);
board[i][j] = words[k];
return res;
}
}
class Solution {
List<List<String>> res = new ArrayList<>();
List<String> path = new ArrayList<>();
public List<List<String>> partition(String s) {
backtrack(s, 0);
return res;
}
public void backtrack(String s, int start) {
if (start >= s.length()) {
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i < s.length(); i++) {
if (isPalindrome(s, start, i)) {
path.add(s.substring(start, i + 1));
} else {
continue;
}
backtrack(s, i + 1);
path.remove(path.size() - 1);
}
}
public boolean isPalindrome(String s, int l, int r) {
while (l < r) {
if (s.charAt(l) != s.charAt(r)) return false;
l++;
r--;
}
return true;
}
}
class Solution {
List<List<String>> res = new ArrayList<>();
List<String> path = new ArrayList<>();
int[] chessboard; // 存储第i行的皇后在第几列
public List<List<String>> solveNQueens(int n) {
chessboard = new int[n];
backtrack(n, 0);
return res;
}
public void backtrack(int n, int r) {
if (path.size() == n) {
res.add(new ArrayList<>(path));
return;
}
for (int c = 0; c < n; c++) {
if (!isValid(r, c)) continue;
StringBuilder sb = new StringBuilder();
for (int j = 0; j < n; j++) {
if (j != c) sb.append('.');
else sb.append('Q');
}
path.add(sb.toString());
chessboard[r] = c;
backtrack(n, r + 1);
path.remove(path.size() - 1);
chessboard[r] = 0;
}
}
private boolean isValid(int row, int col) {
for (int i = 0; i < row; i++) {
if (chessboard[i] == col) return false;
if (chessboard[i] + i == row + col) return false;
if (chessboard[i] - i == col - row) return false;
}
return true;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return left;
}
}
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int left = 0, right = m * n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (matrix[mid / n][mid % n] == target) return true;
else if (matrix[mid / n][mid % n] < target) left = mid + 1;
else right = mid - 1;
}
return false;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1;
int first = -1, last = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
first = mid;
right = mid - 1;
}
else if (nums[mid] > target) right = mid - 1;
else left = mid + 1;
}
left = 0;
right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
last = mid;
left = mid + 1;
}
else if (nums[mid] <= target) left = mid + 1;
else right = mid - 1;
}
if (first == n) return new int[]{-1, -1};
else return new int[]{first, last};
}
}
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) left = mid + 1;
else right = mid;
}
return nums[left];
}
}
找分界点+左右分别查找
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] > nums[right]) left = mid + 1;
else right = mid;
}
int split = left;
if (split == 0) {
return search(nums, target, 0, n - 1);
}
if (nums[0] > target) {
return search(nums, target, split, n - 1);
}
return search(nums, target, 0, split - 1);
}
public int search(int[] nums, int target, int l, int r) {
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) r = mid - 1;
else l = mid + 1;
}
return -1;
}
}
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int left = (m + n + 1) / 2;
int right = (m + n + 2) / 2;
//将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k
return (getKth(nums1, 0, m - 1, nums2, 0, n - 1, left) + getKth(nums1, 0, m - 1, nums2, 0, n - 1, right)) * 0.5;
}
private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
// 让len1长度小于len2,这样能保证如果有数组为空,一定是len1
if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
if (len1 == 0) return nums2[start2 + k - 1];
if (k == 1) return Math.min(nums1[start1], nums2[start2]);
int i = start1 + Math.min(len1, k / 2) - 1;
int j = start2 + Math.min(len2, k / 2) - 1;
if (nums1[i] > nums2[j]) {
return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
} else {
return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}
}
}
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (Character c : s.toCharArray()) {
if (c == '(') stack.push(')');
else if (c == '[') stack.push(']');
else if (c == '{') stack.push('}');
else if (stack.empty() || c != stack.pop()) return false;
}
if (stack.empty()) return true;
return false;
}
}
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();
}
}
class Solution {
public String decodeString(String s) {
Deque<Integer> countStack = new ArrayDeque<>();
Deque<String> stringStack = new ArrayDeque<>();
String curString = "";
int k = 0;
for (char ch : s.toCharArray()) {
if (Character.isDigit(ch)) {
k = k * 10 + (ch - '0'); // 处理多位数
} else if (ch == '[') {
countStack.push(k);
stringStack.push(curString);
curString = "";
k = 0;
} else if (ch == ']') {
// 遇到 ']',解码
StringBuilder temp = new StringBuilder(stringStack.pop());
int repeatTimes = countStack.pop();
for (int i = 0; i < repeatTimes; i++) {
temp.append(curString); // 重复当前字符串
}
curString = temp.toString(); // 更新当前字符串
} else {
// 如果是字母,直接加到当前字符串
curString += ch;
}
}
return curString;
}
}
单调栈
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
Deque<Integer> st = new LinkedList<>();
int[] res = new int[n];
for (int i = 0; i < n; i++) {
int cur = temperatures[i];
while (!st.isEmpty() && cur > temperatures[st.peek()]) {
int preIndex = st.pop();
res[preIndex] = i - preIndex;
}
st.push(i);
}
return res;
}
}
单调栈
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
Deque<Integer> st = new LinkedList<>();
for (int i = 0; i < n; i++) {
int x = heights[i];
while (!st.isEmpty() && x <= heights[st.peek()]) {
st.pop();
}
left[i] = st.isEmpty() ? -1 : st.peek();
st.push(i);
}
int[] right = new int[n];
st.clear();
for (int i = n - 1; i >= 0; i--) {
int x = heights[i];
while (!st.isEmpty() && x <= heights[st.peek()]) {
st.pop();
}
right[i] = st.isEmpty() ? n : st.peek();
st.push(i);
}
int res = 0;
for (int i = 0; i < n; i++) {
res = Math.max(res, heights[i] * (right[i] - left[i] - 1));
}
return res;
}
}
快速选择
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
return quickSelect(nums, n - k, 0, n - 1);
}
public int quickSelect(int[] nums, int k, int l, int r) {
if (l == r) return nums[l];
int i = l - 1, j = r + 1, x = nums[l + r >> 1];
while (i < j) {
do i++; while (nums[i] < x);
do j--; while (nums[j] > x);
if (i < j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
if (k <= j) return quickSelect(nums, k, l, j);
else return quickSelect(nums, k, j + 1, r);
}
}
class Solution {
public int[] topKFrequent(int[] nums, int k) {
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
List<Integer> res = new ArrayList<>();
// 将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
List<Integer>[] list = new List[nums.length + 1];
for (int key : map.keySet()) {
int i = map.get(key);
if (list[i] == null) {
list[i] = new ArrayList<>();
}
list[i].add(key);
}
// 倒序遍历数组获取出现顺序从大到小的排列
for (int i = list.length - 1; i >= 0 && res.size() < k; i--) {
if (list[i] == null) continue;
res.addAll(list[i]);
}
int[] ans = new int[k];
for (int i = 0; i < k; i++) {
ans[i] = res.get(i);
}
return ans;
}
}
class MedianFinder {
Queue<Integer> small, big;
public MedianFinder() {
small = new PriorityQueue<>((x, y) -> (y - x));
big = new PriorityQueue<>(); // 默认是小顶堆,存储较大的一半
// big里的数可能比small里多一个
}
public void addNum(int num) {
if (small.size() == big.size()) {
small.add(num);
big.add(small.poll());
} else {
big.add(num);
small.add(big.poll());
}
}
public double findMedian() {
return small.size() == big.size() ? (small.peek() + big.peek()) / 2.0 : big.peek();
}
}
class Solution {
public int maxProfit(int[] prices) {
int minPrice = prices[0];
int res = 0;
for (int price : prices) {
if (price > minPrice) {
res = Math.max(res, price - minPrice);
} else {
minPrice = price;
}
}
return res;
}
}
class Solution {
public boolean canJump(int[] nums) {
int right = 0;
for (int i = 0; i < nums.length; i++) {
if (i > right) break;
right = Math.max(right, i + nums[i]);
}
return right >= nums.length - 1;
}
}
class Solution {
public int jump(int[] nums) {
int res = 0;
int end = 0;
int right = 0;
// 这里要注意i < nums.length - 1,最后一步肯定跳到终点了
for (int i = 0; i < nums.length - 1; i++) {
right = Math.max(right, i + nums[i]);
if (i == end) {
end = right;
res++;
}
}
return res;
}
}
class Solution {
public List<Integer> partitionLabels(String s) {
int[] last = new int[26];
for (int i = 0; i < s.length(); i++) {
last[s.charAt(i) - 'a'] = i;
}
List<Integer> res = new ArrayList<>();
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
end = Math.max(end, last[s.charAt(i) - 'a']);
if (i == end) {
res.add(end - start + 1);
start = end + 1;
}
}
return res;
}
}
class Solution {
public int climbStairs(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
int c1 = 1;
int c2 = 2;
int res = 0;
for (int i = 3; i <= n; i++) {
res = c1 + c2;
c1 = c2;
c2 = res;
}
return res;
}
}
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> res = new ArrayList<>();
res.add(Arrays.asList(1));
for (int row = 1; row < numRows; row++) {
List<Integer> level = new ArrayList<>();
level.add(1);
for (int i = 1; i < row; i++) {
level.add(res.get(row - 1).get(i - 1) + res.get(row - 1).get(i));
}
level.add(1);
res.add(level);
}
return res;
}
}
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if (n == 1) return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < n; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[n - 1];
}
}
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
int minN = Integer.MAX_VALUE;
for (int j = 1; j * j <= i; j++) {
minN = Math.min(minN, dp[i - j * j]);
}
dp[i] = minN + 1;
}
return dp[n];
}
}
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, 2 * amount);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
class Solution {
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()];
}
}
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = 1;
Arrays.fill(dp, 1);
int res = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
res = Math.max(res, dp[i]);
}
return res;
}
}
class Solution {
public int maxProduct(int[] nums) {
int res = Integer.MIN_VALUE;
int 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]);
res = Math.max(res, imax);
}
return res;
}
}
01背包问题
class Solution {
public boolean canPartition(int[] nums) {
int n = nums.length;
int total = 0;
for (int num : nums) total += num;
if (total % 2 == 1) return false;
int target = total / 2;
int[]dp = new int[target + 1];
for (int i = 1; i <= n; i++) {
for (int j = target; j >= nums[i - 1]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i - 1]] + nums[i - 1]);
}
}
int[][] f = new int[n + 1][target + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= target; j++) {
if (nums[i - 1] > j) {
f[i][j] = f[i - 1][j];
} else {
f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - nums[i - 1]] + nums[i - 1]);
}
}
}
return f[n][target] == target;
}
}
class Solution {
public int longestValidParentheses(String s) {
int res = 0;
int[] dp = new int[s.length()];
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
res = Math.max(res, dp[i]);
}
}
return res;
}
}
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int i = 1; i < n; i++) {
dp[0][i] = dp[0][i - 1] + grid[0][i];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[m - 1][n - 1];
}
}
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 2) return s;
int strLen = s.length();
int maxStart = 0;
int maxEnd = 0;
int maxLen = 1;
boolean[][] dp = new boolean[strLen][strLen];
for (int r = 1; r < strLen; r++) {
for (int l = 0; l < r; l++) {
if (s.charAt(l) == s.charAt(r) &&
(r - l <= 2 || dp[l + 1][r - 1])) { // r - 1 <= 2是精髓
dp[l][r] = true;
if (r - l + 1 > maxLen) {
maxLen = r - l + 1;
maxStart = l;
maxEnd = r;
}
}
}
}
return s.substring(maxStart, maxEnd + 1);
}
}
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
char c1 = text1.charAt(i - 1);
for (int j = 1; j <= n; j++) {
char c2 = text2.charAt(j - 1);
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
}
思路:用 D[i][j]
表示 A
的前 i
个字母和 B
的前 j
个字母之间的编辑距离。
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
if (m == 0 || n == 0) {
return m + n;
}
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i < m + 1; i++) {
dp[i][0] = i;
}
for (int j = 0; j < n + 1; j++) {
dp[0][j] = j;
}
for (int i = 1; i < m + 1; i++) {
for (int j = 1; j < n + 1; j++) {
int left = dp[i - 1][j] + 1;
int up = dp[i][j - 1] + 1;
int up_left = dp[i - 1][j - 1];
if (word1.charAt(i - 1) != word2.charAt(j - 1)) {
up_left += 1;
}
dp[i][j] = Math.min(left, Math.min(up, up_left));
}
}
return dp[m][n];
}
}
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int num : nums) {
res ^= num;
}
return res;
}
}
摩尔计数
class Solution {
public int majorityElement(int[] nums) {
int res = nums[0];
int count = 0;
for (int x : nums) {
if (count == 0) {
res = x;
count++;
continue;
}
if (x == res) count++;
else count--;
}
return res;
}
}
两次遍历
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int p0 = 0, p2 = n - 1;
for (int i = 0; i <= p2; i++) {
while (i <= p2 && nums[i] == 2) {
int tmp = nums[i];
nums[i] = nums[p2];
nums[p2] = tmp;
p2--;
}
if (nums[i] == 0) {
int tmp = nums[i];
nums[i] = nums[p0];
nums[p0] = tmp;
p0++;
}
}
}
}
一次遍历:1正常处理,0要特殊处理
class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int p0 = 0, p1 = 0;
for (int i = 0; i < n; i++) {
if (nums[i] == 1) {
swap(nums, i, p1);
p1++;
} else if (nums[i] == 0) {
swap(nums, i, p0);
if (p0 < p1) {
swap(nums, i, p1);
}
p0++;
p1++;
}
}
}
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
class Solution {
public void nextPermutation(int[] nums) {
// 134652
int n = nums.length;
if (n <= 1) return;
// 1.倒序找到46的位置,确定较小的数4
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
// 若i<0则已经到达了最后一个排列
if (i >= 0) {
// 2.倒序找到第一个比4大的数
int j = n - 1;
while (j >= 0 && nums[i] >= nums[j]) j--;
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
// 135642
// 3.翻转4后面的数,使其递增排列 135246
int left = i + 1;
int right = n - 1;
while (left < right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left++;
right--;
}
}
}
快慢指针,找环入口
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}