【算法康复训练①】剑指offer P1

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;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心海非海_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值