1.剑指 Offer 68 - II. 二叉树的最近公共祖先 2022.7.17
力扣算法 Java 刷题笔记【二叉树篇】hot100(十)GIT原理之最近公共祖先(二叉树的最近公共祖先)中等 1
五个变式
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
if (root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null && right == null) {
return null;
}
if (left != null && right != null) {
return root;
}
return left == null ? right : left;
}
}
/*
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
if (root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null) {
return right;
}
if (right == null) {
return left;
}
return root;
}
}
*/
剑指 Offer 10- I. 斐波那契数列 2022.7.17
力扣算法 Java 刷题笔记【动态规划篇 DP】hot100(一)动态规划解题核心框架 & 斐波那契数 & 零钱兑换 5
解法一:自顶向下(备忘录)–递归
class Solution {
// static final int MOD = 1000000007;
int[] memo = null;
public int fib(int n) {
if (n <= 1) {
return n;
}
if (memo == null) {
memo = new int[n + 1];
}
if (memo[n] != 0) {
return memo[n];
}
memo[n] = fib(n - 1) + fib(n - 2); // 取模 memo[n] = (fib(n - 1) + fib(n - 2)) % MOD;
return memo[n];
}
}
解法二:自底向上(dp)–迭代
class Solution {
public int fib(int n) {
if (n == 0) {
return 0;
}
int[] dp = new int[n + 1];
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]; // 取模 dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
}
return dp[n];
}
}
剑指 Offer 10- II. 青蛙跳台阶问题 2022.7.17
力扣算法 Java 刷题笔记【动态规划篇 DP】hot100(一)动态规划解题核心框架 & 斐波那契数 & 零钱兑换 5
class Solution {
static final int MOD = 1000000007;
public int numWays(int n) {
if (n <= 1) {
return 1;
}
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]) % MOD;
}
return dp[n];
}
}
剑指 Offer 25. 合并两个排序的链表 2022.7.17
力扣算法 Java 刷题笔记【链表篇】hot100(一)合并 K 个升序链表(困难) 删除链表的倒数第 N 个结点(中等) 7
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1), p = dummy;
while (l1 != null && l2 != null) {
if (l1.val > l2.val) {
p.next = l2;
l2 = l2.next;
} else {
p.next = l1;
l1 = l1.next;
}
p = p.next;
}
if (l1 == null) {
p.next = l2;
}
if (l2 == null) {
p.next = l1;
}
return dummy.next;
}
}
剑指 Offer 24. 反转链表 2022.7.17
力扣算法 Java 刷题笔记【链表篇】hot100(二)递归反转链表的一部分 4
解法一:递归
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
解法二:迭代
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null, cur = head, nxt = head;
while (cur != null) {
nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
}
剑指 Offer 27. 二叉树的镜像 2022.7.18
力扣算法 Java 刷题笔记【二叉树篇】hot100(一)翻转二叉树 填充每个节点的下一个右侧节点指针(中等) 二叉树展开为链表(中等)3
// 后序遍历
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode left = mirrorTree(root.left);
TreeNode right = mirrorTree(root.right);
TreeNode node = new TreeNode();
node = left;
root.left = right;
root.right = node;
return root;
}
}
/*
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode node = root.left;
root.left = mirrorTree(root.right);
root.right = mirrorTree(node);
return root;
}
}
*/
/* 前序遍历
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode node = root.left;
root.left = root.right;
root.right = node;
mirrorTree(root.left);
mirrorTree(root.right);
return root;
}
}
*/
剑指 Offer 55 - I. 二叉树的深度 2022.7.18
力扣算法 Java 刷题笔记【二叉树篇】hot100(十三) 二叉树的最大深度 对称二叉树 相同的树 3
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftMax = maxDepth(root.left);
int rightMax = maxDepth(root.right);
return Math.max(leftMax, rightMax) + 1; // return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
}
剑指 Offer 29. 顺时针打印矩阵 2022.7.18
力扣算法 Java 刷题笔记【数组篇】hot100(五)二维数组的花式遍历 3
class Solution {
public int[] spiralOrder(int[][] matrix) {
int m = matrix.length;
if (m == 0) {
return new int[0];
}
int n = matrix[0].length;
int upper_bound = 0, lower_bound = m - 1;
int left_bound = 0, right_bound = n - 1;
int[] res = new int[m * n];
res[m * n - 1] = -1;
int id = 0;
while (res[m * n - 1] == -1) { // 注意循环条件-->此处仍有改进空间
if (upper_bound <= lower_bound) {
for (int i = left_bound; i <= right_bound; i++) {
res[id++] = matrix[upper_bound][i];
}
upper_bound++;
}
if (left_bound <= right_bound) {
for (int i = upper_bound; i <= lower_bound; i++) {
res[id++] = matrix[i][right_bound];
}
right_bound--;
}
if (upper_bound <= lower_bound) {
for (int i = right_bound; i >= left_bound; i--) {
res[id++] = matrix[lower_bound][i];
}
lower_bound--;
}
if (left_bound <= right_bound) {
for (int i = lower_bound; i >= upper_bound; i--) {
res[id++] = matrix[i][left_bound];
}
left_bound++;
}
}
return res;
}
}
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 2022.7.18
五个变式
方法一:同二叉树(题1)
方法二:利用二叉搜索树的性质
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
int val1 = Math.min(p.val, q.val);
int val2 = Math.max(p.val, q.val);
return find(root, val1, val2);
}
public TreeNode find(TreeNode root, int val1, int val2) {
if (root == null) {
return null;
}
if (val1 > root.val) {
return find(root.right, val1, val2);
}
if (val2 < root.val) {
return find(root.left, val1, val2);
}
return root;
}
}
[剑指 Offer 52. 两个链表的第一个公共节点](https://leetcode.cn/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/ 2022.7.19
力扣算法 Java 刷题笔记【链表篇】hot100(一)合并 K 个升序链表(困难) 删除链表的倒数第 N 个结点(中等) 7
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA, p2 = headB;
while (p1 != p2) {
if (p1 == null) {
p1 = headB;
} else {
p1 = p1.next;
}
if (p2 == null) {
p2 = headA;
} else {
p2 = p2.next;
}
}
return p1;
}
}
剑指 Offer 28. 对称的二叉树 2022.7.19
力扣算法 Java 刷题笔记【二叉树篇】hot100(十三) 二叉树的最大深度 对称二叉树 相同的树 3
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return check(root.left, root.right);
}
boolean check(TreeNode left, TreeNode right) {
if (left == null || right == null) {
return left == right;
}
if (left.val != right.val) {
return false;
}
return check(left.left, right.right) && check(left.right, right.left);
}
}
剑指 Offer 48. 最长不含重复字符的子字符串 2022.7.19
力扣算法 Java 刷题笔记【数组篇 滑动窗口算法】hot100(四)最小覆盖子串、字符串的排列、异位词、 无重复字符的最长子串 4
class Solution {
public int lengthOfLongestSubstring(String s) {
HashMap<Character, Integer> window = new HashMap<>();
int l = 0, r = 0;
int res = 0;
while (r < s.length()) {
char c = s.charAt(r);
window.put (c, window.getOrDefault(c, 0) + 1);
r++;
while (window.get(c) > 1) {
window.put(s.charAt(l), window.get(s.charAt(l)) - 1);
l++;
}
res = Math.max(res, r - l);
}
return res;
}
}
剑指 Offer 42. 连续子数组的最大和 2022.7.19
力扣算法 Java 刷题笔记【动态规划篇 DP 子序列类型问题】hot100(二) LIS 最长递增子序列及其变形 3
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);
}
int res = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
res = Math.max(dp[i], res);
}
return res;
}
}
剑指 Offer 06. 从尾到头打印链表 2022.7.20
力扣算法 Java 刷题笔记【链表篇】hot100(二)递归反转链表的一部分 4
最优解:时间 O(n) 空间 O(1)
从右边往左填充
public int[] reversePrint(ListNode head) {
if(head == null)
return new int[0];
// 统计链表节点个数,方便创建数组
int count = 0;
ListNode temp = head;
while(temp != null){
count++;
temp = temp.next;
}
int[] res = new int[count];
int k = count - 1;
// 从右往左填充数组
while(head != null){
res[k--] = head.val;
head = head.next;
}
return res;
}
方法一:反转后取值
class Solution {
int count = 0;
public int[] reversePrint(ListNode head) {
if (head == null) {
return new int[0];
}
ListNode last = reverseNode(head);
int[] res = new int[count];
for (int i = 0; last != null; i++) {
res[i] = last.val;
last = last.next;
}
return res;
}
ListNode reverseNode(ListNode head) {
count++;
if (head == null || head.next == null) {
return head;
}
ListNode last = reverseNode(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
方法二:栈
class Solution {
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack = new Stack<ListNode>();
ListNode temp = head;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
int size = stack.size();
int[] print = new int[size];
for (int i = 0; i < size; i++) {
print[i] = stack.pop().val;
}
return print;
}
}
剑指 Offer 18. 删除链表的节点 2022.7.20
力扣算法 Java 刷题笔记【链表篇】hot100(一)合并 K 个升序链表(困难) 删除链表的倒数第 N 个结点(中等) 7
方法一:常规解法
class Solution {
public ListNode deleteNode(ListNode head, int val) {
ListNode res = head;
if (head.val == val) {
return head.next;
}
while (head != null) {
if (head.next == null) {
break;
}
if (head.next.val == val) {
head.next = head.next.next;
}
head = head.next;
}
return res;
}
}
方法二:递归
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head == null) {
return null;
}
if (head.val == val) {
return head.next;
} else {
head.next = deleteNode(head.next, val);
}
return head;
}
}
方法三:双指针
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head.val == val) {
return head.next;
}
ListNode pre = head, cur = head.next;
while (cur != null && cur.val != val) {
pre = cur;
cur = cur.next;
}
if (cur != null) {
pre.next = cur.next;
}
return head;
}
}
剑指 Offer 09. 用两个栈实现队列 2022.7.20
class CQueue {
private Stack<Integer> s1, s2;
public CQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void appendTail(int value) {
s1.push(value);
}
public int deleteHead() {
if (s2.isEmpty()) {
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
}
if (s2.size() == 0) {
return -1;
}
return s2.pop();
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
剑指 Offer 64. 求1+2+…+n 2022.7.20
class Solution {
int res = 0;
public int sumNums(int n) {
if (n == 1) {
return 1;
}
res = n + sumNums(n - 1);
return res;
}
}
树->遍历框架
链表->双指针、虚拟头节点
注意边界
剑指 Offer 55 - II. 平衡二叉树 2022.7.21
class Solution {
public boolean isBalanced(TreeNode root) {
maxDeepth(root);
return isBalancedTree;
}
boolean isBalancedTree = true;
int maxDeepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftMaxDeepth = maxDeepth(root.left);
int rightMaxDeepth = maxDeepth(root.right);
if (Math.abs(leftMaxDeepth - rightMaxDeepth) > 1) {
isBalancedTree = false;
}
return 1 + Math.max(leftMaxDeepth, rightMaxDeepth);
}
}
剑指 Offer 05. 替换空格 2022.7.21
class Solution {
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ') {
sb.append("%20");
}else {
sb.append(c);
}
}
return sb.toString();
}
}
剑指 Offer 54. 二叉搜索树的第k大节点 2022.7.21
力扣算法 Java 刷题笔记【二叉搜索树 BST 篇】hot100(一)BST 中序遍历的应用: BST 第 K 小的元素(中等)二叉搜索树转化累加树(中等)3
class Solution {
public int kthLargest(TreeNode root, int k) {
traverse(root, k);
return res;
}
int i = 0, res = 0;
void traverse(TreeNode root, int k) {
if (root == null) {
return;
}
traverse(root.right, k);
i++;
if (i == k) {
res = root.val;
return;
}
traverse(root.left, k);
}
}
剑指 Offer 22. 链表中倒数第k个节点 2022.7.21
力扣算法 Java 刷题笔记【链表篇】hot100(一)合并 K 个升序链表(困难) 删除链表的倒数第 N 个结点(中等) 7
方法一:栈
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
Stack<ListNode> sk = new Stack<>();
while (head != null) {
sk.push(head);
head = head.next;
}
for (int i = 1; i < k; i++) {
sk.pop();
}
return sk.pop();
}
}
方法二:双指针
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode slow = head, fast = head;
for (int i = 0; i < k; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
剑指 Offer 03. 数组中重复的数字 2022.7.21
哈希表:时间 O(n) 空间 O(n) 我们更关注时间复杂度
class Solution {
public int findRepeatNumber(int[] nums) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int val = nums[i];
hashMap.put(val, hashMap.getOrDefault(val, 0) + 1);
if (hashMap.get(val) > 1) {
return val;
}
}
return -1;
}
}
最优解:
下标法:时间 O(n) 空间 O(1) —> 看到 0~n-1 联想下标法
下标法:通过不停交换元素,使得元素和它所对应的下标相等: nums[i] = i
public int findRepeatNumber(int[] nums) {
// 遍历数组
for(int i = 0; i < nums.length; i++) {
// 之所以用while,是因为交换之后,改位置的元素任然没有在正确的位置
while(i != nums[i]){
if(nums[i] == nums[nums[i]]){
return nums[i];
}
// nums[i] 正确的位置在 nums[nums[i]]
int k = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = k;
}
}
return -1;
}
剑指 Offer 04. 二维数组中的查找 2022.7.21
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix.length == 0) { //matrix == null || matrix.length <= 0 || matrix[0].length <= 0
return false;
}
int n = matrix.length, m = matrix[0].length;
int row = 0, col = m - 1;
while (row < n && col >= 0) {
if (matrix[row][col] > target) {
col--;
} else if (matrix[row][col] < target) {
row++;
} else {
return true;
}
}
return false;
}
}
剑指 Offer 07. 重建二叉树 2022.7.22
力扣算法 Java 刷题笔记【二叉树篇】hot100(二)最大二叉树(中等) 从前序与中序遍历序列构造二叉树(中等) 3
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return build(preorder, 0, preorder.length - 1,
inorder, 0, inorder.length - 1);
}
TreeNode build(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd) {
if (preStart > preEnd || inStart > inEnd) {
return null;
}
int index = 0, rootVal = preorder[preStart];
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootVal) {
index = i;
break;
}
}
int leftSize = index - inStart;
TreeNode root = new TreeNode(rootVal);
root.left = build(preorder, preStart + 1, preStart + leftSize,
inorder, inStart, index - 1);
root.right = build(preorder, preStart + leftSize + 1, preEnd,
inorder, index + 1, inEnd);
return root;
}
}
剑指 Offer 17. 打印从1到最大的n位数 2022.7.22
class Solution {
public int[] printNumbers(int n) {
int max = (int)Math.pow(10, n);
int[] res = new int[max - 1];
for (int i = 0; i < max - 1; i++) {
res[i] = i + 1;
}
return res;
}
}
大数问题:
剑指 Offer 15. 二进制中1的个数 2022.7.24
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int res = 0;
while (n != 0) {
n = n & (n - 1);
res++;
}
return res;
}
}
剑指 Offer 13. 机器人的运动范围 2022.7.24
力扣算法 Java 刷题笔记【DFS篇】hot100(三)岛屿问题(一) 3
力扣算法 Java 刷题笔记【DFS篇】hot100(三)岛屿问题(二) 2|1
class Solution {
int res = 0;
public int movingCount(int m, int n, int k) {
boolean[][] visited = new boolean[m][n];
dfs(m, n, 0, 0, k, visited);
return res;
}
void dfs(int m, int n, int i, int j, int k, boolean[][] visited) {
if (i < 0 || j < 0 || i > m - 1 || j > n - 1) {
return;
}
if (i / 10 + i % 10 + j / 10 + j % 10 > k) {
return;
}
if (visited[i][j] == true) {
return;
}
res++;
visited[i][j] = true;
dfs(m, n, i - 1, j, k, visited);
dfs(m, n, i + 1, j, k, visited);
dfs(m, n, i, j - 1, k, visited);
dfs(m, n, i, j + 1, k, visited);
}
}
剑指 Offer 26. 树的子结构 2022.7.24
力扣算法 Java 刷题笔记【二叉树篇】hot100(十三) 二叉树的最大深度 对称二叉树 相同的树 3
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if (A == null || B == null) {
return A == B;
}
if (A.val == B.val && check(A, B)) {
return true;
}
return isSubStructure(A.left, B) || isSubStructure(A.right, B);
}
boolean check(TreeNode A, TreeNode B) {
if (B == null) {
return true;
}
if (A == null && B != null) {
return false;
}
if (A.val != B.val) {
return false;
}
return check(A.left, B.left) && check(A.right, B.right);
}
}
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 2022.7.24
力扣算法 Java 刷题笔记【数组篇】hot100(三)去除有序数组的重复元素 4
class Solution {
public int[] exchange(int[] nums) {
int slow = 0, fast = 0;
while (fast < nums.length) {
if (nums[fast] % 2 == 1) {
int temp = nums[slow];
nums[slow] = nums[fast];
nums[fast] = temp;
slow++;
}
fast++;
}
return nums;
}
}
剑指 Offer 32 - II. 从上到下打印二叉树 II 2022.7.25
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
List<Integer> temp = new LinkedList<>();
int sz = q.size();
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
temp.add(cur.val);
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
res.add(temp);
}
return res;
}
}
剑指 Offer 57. 和为s的两个数字 2022.7.25
力扣算法 Java 刷题笔记【nSum 问题】hot100(一)团灭 nSum 3
class Solution {
public int[] twoSum(int[] nums, int target) {
int slow = 0, fast = nums.length - 1;
while (slow < fast) {
int sum = nums[slow] + nums[fast];
if (sum < target) {
slow++;
}
if (sum > target) {
fast--;
}
if (sum == target) {
return new int[]{nums[slow], nums[fast]};
}
}
return null;
}
}
剑指 Offer 16. 数值的整数次方 2022.7.25
class Solution {
public double myPow(double x, int n) {
if (n == 0) {
return 1;
}
if (n == Integer.MIN_VALUE) {
return myPow(1 / x, -(n + 1)) / x;
}
if (n < 0) {
return myPow(1 / x, -n);
}
if (n % 2 == 1) {
return myPow(x, n - 1) * x;
}
if (n % 2 == 0) {
double sub = myPow(x, n / 2);
return sub * sub;
}
return -1;
// if (n % 2 == 1) {
// return myPow(x, n - 1) * x;
// } else {
// double sub = myPow(x, n / 2);
// return sub * sub;
// }
}
}
剑指 Offer 32 - I. 从上到下打印二叉树 2022.7.25
class Solution {
public int[] levelOrder(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null) {
return new int[0];
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
res.add(cur.val);
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
// return res.stream().mapToInt(Integer::valueOf).toArray();
int[] ans = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
ans[i] = res.get(i);
}
return ans;
}
}
剑指 Offer 32 - III. 从上到下打印二叉树 III 2022.7.25
双端对列
复杂情况还是用笔画一画,更清晰->辅助分析
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Deque<TreeNode> dq = new LinkedList<>();
dq.offer(root);
int count = 0;
while (!dq.isEmpty()) {
List<Integer> temp = new LinkedList<>();
int sz = dq.size();
if (count % 2 == 0) {
for (int i = 0; i < sz; i++) {
TreeNode cur = dq.pollFirst();
temp.add(cur.val);
if (cur.left != null) {
dq.offerLast(cur.left);
}
if (cur.right != null) {
dq.offerLast(cur.right);
}
}
}
if (count % 2 == 1) {
for (int i = 0; i < sz; i++) {
TreeNode curr = dq.pollLast();
temp.add(curr.val);
if (curr.right != null) {
dq.offerFirst(curr.right);
}
if (curr.left != null) {
dq.offerFirst(curr.left);
}
}
}
count++;
res.add(temp);
}
return res;
}
}
剑指 Offer 30. 包含min函数的栈 2022.7.26
class MinStack {
Stack<Integer> sk = new Stack<>();
Stack<Integer> minStack = new Stack<>();
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
if (minStack.isEmpty() || x <= minStack.peek()) {
minStack.push(x);
}
sk.push(x);
}
public void pop() {
if (minStack.peek().equals(sk.peek())) {
minStack.pop();
}
sk.pop();
}
public int top() {
return sk.peek();
}
public int min() {
return minStack.peek();
}
}
剑指 Offer 38. 字符串的排列 2022.7.26
力扣算法 Java 刷题笔记【回溯算法篇 DFS】hot100(一)全排列 、子集 、组合 4
class Solution {
public String[] permutation(String s) {
permutaUnique(s.toCharArray());
String[] arr = new String[res.size()];
for (int i = 0; i < res.size(); i++) {
arr[i] = res.get(i);
}
return arr;
}
List<String> res = new LinkedList<>();
boolean[] used;
StringBuilder track = new StringBuilder();
public List<String> permutaUnique(char[] nums) {
Arrays.sort(nums);
used = new boolean[nums.length];
backtrack(nums);
return res;
}
void backtrack(char[] nums) {
if (track.length() == nums.length) {
res.add(track.toString());
return;
}
for (int i = 0; i < nums.length; i++) {
if (used[i] == true) {
continue;
}
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
track.append(nums[i]);
used[i] = true;
backtrack(nums);
track.deleteCharAt(track.length() - 1);
used[i] = false;
}
}
}
剑指 Offer 36. 二叉搜索树与双向链表 2022.7.26
class Solution {
Node pre, head;
public Node treeToDoublyList(Node root) {
if (root == null) {
return null;
}
traverse(root);
head.left = pre;
pre.right = head;
return head;
}
void traverse(Node root) {
if (root == null) {
return;
}
traverse(root.left);
if (pre == null) {
head = root;
} else {
pre.right = root;
root.left = pre;
}
pre = root;
traverse(root.right);
}
}
剑指 Offer 53 - II. 0~n-1中缺失的数字 2022.7.26
力扣算法 Java 刷题笔记【数组篇 二分搜索】hot100(一)二分查找、搜索插入位置、在排序数组中查找元素的第一个和最后一个位置 3
class Solution {
public int missingNumber(int[] nums) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] > mid) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
}
剑指 Offer 11. 旋转数组的最小数字 2022.7.26
class Solution {
public int minArray(int[] numbers) {
int l = 0, r = numbers.length - 1;
while (l < r) {
if (numbers[l] < numbers[r]) {
return numbers[l];
}
int mid = l + (r - l) / 2;
if (numbers[mid] > numbers[l]) {
l = mid + 1;
} else if (numbers[mid] < numbers[l]) {
r = mid;
} else {
l++;
}
}
return numbers[l];
}
}
剑指 Offer 65. 不用加减乘除做加法 2022.7.27
class Solution {
public int add(int a, int b) {
if(a == 0 || b == 0) {
return a == 0 ? b : a;
}
// 设 a = 1001
// 设 b = 0101
// 求和 1100
int sum = a ^ b;
// 进位 0001 << 1 = 0010
int carry = (a & b) << 1;
// add(1100, 0010)
return add(sum, carry);
}
}
剑指 Offer 14- I. 剪绳子 2022.7.28
class Solution {
public int cuttingRope(int n) {
if (n <= 2) {
return 1;
}
if (n == 3) {
return 2;
}
if (n == 4) {
return 4;
}
int res = n / 3;
int mod = n % 3;
if (n % 3 == 0) {
return (int)Math.pow(3, res);
} else if (n % 3 == 1) {
return (int)(Math.pow(3, res - 1) * 4);
} else {
return (int)(Math.pow(3, res) * 2);
}
}
}
剑指 Offer 14- II. 剪绳子 II 2022.7.28
class Solution {
public int cuttingRope(int n) {
if (n < 4) {
return n - 1;
}
int res = n / 3;
int mod = n % 3;
int p = 1000000007;
if (mod == 0) {
return (int)(pow(3, res));
} else if (mod == 1) {
return (int)(pow(3, res - 1) * 4 % p);
} else {
return (int)(pow(3, res) * 2 % p);
}
}
long pow (int a, int n) {
long sum = 1;
int p = 1000000007;
for (int i = 0; i < n; i++) {
sum = sum * a % p;
}
return sum;
}
}
剑指 Offer 33. 二叉搜索树的后序遍历序列 2022.7.28
class Solution {
public boolean verifyPostorder(int[] postorder) {
return verify(postorder, 0, postorder.length - 1);
}
boolean verify(int[] postorder, int start, int end) {
if (start >= end) {
return true;
}
int p = start;
while (postorder[p] < postorder[end]) {
p++;
}
int m = p;
while (postorder[m] > postorder[end]) {
m++;
}
return m == end && verify(postorder, start, p - 1) && verify(postorder, p, m - 1);
}
}
剑指 Offer 50. 第一个只出现一次的字符 2022.7.28
class Solution {
public char firstUniqChar(String s) {
int[] nums = new int[26];
for (int i = 0; i < s.length(); i++) {
nums[s.charAt(i) - 'a']++;
}
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (nums[c - 'a'] == 1) {
return c;
}
}
return ' ';
}
}
剑指 Offer 34. 二叉树中和为某一值的路径 2022.7.28
class Solution {
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int target) {
if (root == null) {
return res;
}
dfs(root, target, new LinkedList<>());
return res;
}
void dfs(TreeNode root, int sum, LinkedList<Integer> path) {
if (root == null) {
return;
}
sum = sum - root.val;
if (root.left == null && root.right == null) {
if (sum == 0) {
path.addLast(root.val);
res.add(new LinkedList<>(path));
path.removeLast();
}
return;
}
path.addLast(root.val);
dfs(root.left, sum, path);
path.removeLast();
path.addLast(root.val);
dfs(root.right, sum, path);
path.removeLast();
}
}
剑指 Offer 53 - I. 在排序数组中查找数字 I 2022.7.29
力扣算法 Java 刷题笔记【数组篇 二分搜索】hot100(一)二分查找、搜索插入位置、在排序数组中查找元素的第一个和最后一个位置 3
class Solution {
public int search(int[] nums, int target) {
int left_index = left_bound(nums, target);
if (left_index == -1) {
return 0;
}
int right_index = right_bound(nums, target);
return right_index - left_index + 1;
}
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
right = mid - 1;
}
}
if (left >= nums.length || nums[left] != target) {
return -1;
}
return left;
}
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
left = mid + 1;
}
}
if (right < 0 || nums[right] != target) {
return -1;
}
return right;
}
}
剑指 Offer 40. 最小的k个数 2022.7.29
力扣算法 Java 刷题笔记【快速排序】hot100(一)快速排序 快速选择算法 1
方法一:优先队列
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0 || arr.length == 0) {
return new int[0];
}
PriorityQueue<Integer> pq = new PriorityQueue<>();
int[] res = new int[k];
int i = 0;
for (int a : arr) {
pq.offer(a);
if (pq.size() > arr.length - k) {
res[i] = pq.poll();
i++;
}
}
return res;
}
}
******** 另一种写法
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0 || arr.length == 0) {
return new int[0];
}
// 默认是小根堆,实现大根堆需要重写一下比较器。
Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> v2 - v1);
for (int num: arr) {
if (pq.size() < k) {
pq.offer(num);
} else if (num < pq.peek()) {
pq.poll();
pq.offer(num);
}
}
int[] res = new int[pq.size()];
int idx = 0;
for(int num: pq) {
res[idx++] = num;
}
return res;
}
}
方法二:快排
剑指 Offer 39. 数组中出现次数超过一半的数字 2022.7.29
摩尔投票法(对拼消耗)
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
int candicate = 0;
for (int num : nums) {
if (count == 0) {
candicate = num;
}
count += candicate == num ? 1 : -1;
}
return candicate;
}
}
剑指 Offer 12. 矩阵中的路径 2022.7.31
class Solution {
int m = 0, n = 0, len = 0;
public boolean exist(char[][] board, String word) {
m = board.length;
n = board[0].length;
len = word.length();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(board, i, j, word, 0)) {
return true;
}
}
}
return false;
}
boolean dfs(char[][] board, int i, int j, String word, int k) {
if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != word.charAt(k)) {
return false;
}
if (k == len - 1) {
return true;
}
board[i][j] = '\n';
boolean res = dfs(board, i - 1, j, word, k + 1) ||
dfs(board, i + 1, j, word, k + 1) ||
dfs(board, i, j - 1, word, k + 1) ||
dfs(board, i, j + 1, word, k + 1);
board[i][j] = word.charAt(k);
return res;
}
}
剑指 Offer 19. 正则表达式匹配 2022.7.31
https://www.bilibili.com/video/BV1jd4y1U7kE/?spm_id_from=pageDriver&vd_source=28639105a09afd80125a0dc2b769abba
https://www.iamshuaidi.com/275.html
https://offer.iamshuaidi.com/84.html
class Solution {
public boolean isMatch(String s, String p) {
int n = s.length();
int m = p.length();
boolean[][] dp = new boolean[n + 1][m + 1]; // 默认是 false
dp[0][0] = true;
for (int j = 2; j <= m; j++) {
if (p.charAt(j - 1) == '*') { // * 可以等于 0
dp[0][j] = dp[0][j - 2];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (p.charAt(j - 1) != '*') {
if (p.charAt(j - 1) == '.' || p.charAt(j - 1) == s.charAt(i - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = false;
}
} else { // 当 j = 1 时 由于第一位不可能为 '*' 故不会进入这个逻辑, j - 2 就不会越界
if (p.charAt(j - 2) != s.charAt(i - 1) && p.charAt(j - 2) != '.') {
dp[i][j] = dp[i][j - 2];
} else {
dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 1] || dp[i - 1][j];
}
}
}
}
return dp[n][m];
}
}
剑指 Offer 58 - II. 左旋转字符串 2022.7.31
方法一:
class Solution {
public String reverseLeftWords(String s, int n) {
int len = s.length();
StringBuilder sb = new StringBuilder(s);
reverseString(sb,0,n-1);
reverseString(sb,n,len-1);
return sb.reverse().toString();
}
public void reverseString(StringBuilder sb, int start, int end) {
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
}
}
方法二:
class Solution {
public String reverseLeftWords(String s, int n) {
return s.substring(n) + s.substring(0, n);
}
}
剑指 Offer 57 - II. 和为s的连续正数序列 2022.7.31
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> list = new LinkedList<>();
for (int l = 1, r = 1, sum = 0; r < target; r++) {
sum += r;
while (sum > target) {
sum -= l;
l++;
}
if (sum == target) {
int[] temp = new int[r - l + 1];
for (int i = 0; i < temp.length; i++) {
temp[i] = l + i;
}
list.add(temp);
}
}
int[][] ans = new int[list.size()][];
for (int i = 0; i < list.size(); i++) {
ans[i] = list.get(i);
}
return ans;
}
}
剑指 Offer 31. 栈的压入、弹出序列
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
if(pushed == null || pushed.length <= 0){
return true;
}
int k = 0;
Stack<Integer> stack = new Stack();
for(int i = 0; i < pushed.length; i++){
stack.push(pushed[i]);
while(!stack.isEmpty() && stack.peek() == popped[k]){
stack.pop();
k++;
}
}
return stack.isEmpty();
}
}