算法汇总(剑指)

文章目录

1. 二叉树的最近公共祖先

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;
    }
}
*/

2. 斐波那契数列

剑指 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];
    }
}

3. 青蛙跳台阶问题

剑指 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];
    }
}

4. 合并两个排序的链表

剑指 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;
    }
}

5. 反转链表

剑指 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;
    }
}

6. 二叉树的镜像

剑指 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;
    }
}
*/

7. 二叉树的深度

剑指 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;
    }
}

8. 顺时针打印矩阵

剑指 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;
    }
}

9. 二叉搜索树的最近公共祖先

剑指 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;
    }
}

10. 两个链表的第一个公共节点

[剑指 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;
    }
}

11. 对称的二叉树

剑指 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);
    }
}

12. 最长不含重复字符的子字符串

剑指 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;
    }
}

13. 连续子数组的最大和(最大子数组和)

剑指 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;
    }
}

14. 从尾到头打印链表

剑指 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;
    }
}

15. 删除链表的节点

剑指 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;
    }
}

16. 用两个栈实现队列

剑指 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();
 */

17. 求1+2+…+n

剑指 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;
    }
}

树->遍历框架
链表->双指针、虚拟头节点
注意边界

18. 平衡二叉树

剑指 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);
    }
}

19. 替换空格

剑指 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();
    }
}

20. 二叉搜索树的第k大节点

剑指 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);
    }
}

21. 链表中倒数第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;
    }
}

22. 数组中重复的数字

剑指 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;
}

23. 二维数组中的查找

剑指 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;
    }
}

24. 前序和中序遍历->构建二叉树(重建二叉树)

剑指 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;
    }
}

25. 打印从1到最大的n位数

剑指 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;
    }
}

大数问题:


26. 二进制中1的个数

剑指 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;
    }
}

27. 机器人的运动范围

剑指 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);
    }
}

28. 树的子结构

剑指 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);
    }
}

29. 调整数组顺序使奇数位于偶数前面

剑指 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;
    }
}

30. 二叉树层序遍历

剑指 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;
    }
}

31. 和为s的两个数字

剑指 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;
    }
}

32. 数值的整数次方

剑指 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;
        // }
    }
}

33. 从上到下打印二叉树

剑指 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;
    }
}

34. 从上到下打印二叉树 III

剑指 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;
    }
}


35. 包含min函数的栈

剑指 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();
    }
}

36. 字符串的排列

剑指 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;
        }
    }
}

37. 二叉搜索树与双向链表

剑指 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);
    }
}

38. 0~n-1中缺失的数字

剑指 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;
    }
}

39. 旋转数组的最小数字【高频】

剑指 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];
    }
}

40. 不用加减乘除做加法

剑指 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);
    }
}

41. 剪绳子

剑指 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);
        }
    }
}

42. 剪绳子 II

剑指 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;
    }

}

43. 二叉搜索树的后序遍历序列

剑指 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);
    }
}

44. 第一个只出现一次的字符

剑指 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 ' ';
    }
}

45. 二叉树中和为某一值的路径

剑指 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();
    }
}

46. 在排序数组中查找数字 I

剑指 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;
    }
}

47. 最小的k个数

剑指 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;
    }
}

方法二:快排

48. 数组中出现次数超过一半的数字

剑指 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;
    }
}

49. 矩阵中的路径

剑指 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;
    }
}

50. 正则表达式匹配

剑指 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];
    }
}

51. 左旋转字符串

剑指 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);
    }
}

52. 和为s的连续正数序列

剑指 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;
    }
}

53. 栈的压入、弹出序列

剑指 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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心海非海_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值