• 力扣记录:Hot100(5)——102-141


    102 二叉树的层序遍历

    • 队列,之前做过
      • 时间复杂度O(n),空间复杂度O(n)
    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            //队列
            Queue<TreeNode> queue = new LinkedList<>();
            List<List<Integer>> result = new ArrayList<>();
            if(root == null) return result;
            queue.offer(root);
            while(!queue.isEmpty()){
                int leng = queue.size();    //本层长度
                List<Integer> path = new ArrayList<>();
                for(int i = 0; i < leng; i++){  //记录本层元素
                    TreeNode cur = queue.poll();
                    path.add(cur.val);
                    if(cur.left != null) queue.offer(cur.left);
                    if(cur.right != null) queue.offer(cur.right);
                }
                result.add(new ArrayList(path));
            }
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    104 二叉树的最大深度

    • 递归,之前做过,可直接在原函数上递归,优化终止条件
      • 时间复杂度O(n),空间复杂度O(|二叉树高度|)
    class Solution {
        public int maxDepth(TreeNode root) {
            //递归
            if(root == null) return 0;
            return countDepth(root, 1);
        }
        //递归函数,输入根节点和当前深度
        private int countDepth(TreeNode root, int depth){
            //终止条件
            if(root.left == null && root.right == null) return depth;
            //后序遍历
            int left = root.left == null ? depth : countDepth(root.left, depth + 1);
            int right = root.right == null ? depth : countDepth(root.right, depth + 1);
            return Math.max(left, 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    105 从前序与中序遍历序列构造二叉树

    • 递归,之前做过,注意边界,左闭右闭
      • 时间复杂度O(n),空间复杂度O(n)
    class Solution {
        public TreeNode buildTree(int[] preorder, int[] inorder) {
            //递归
            return buildTree1(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
        }
        //递归函数,输入前序数组及其左右边界,中序数组及其左右边界(左闭右闭)
        private TreeNode buildTree1(int[] preorder, int preLeft, int preRight, int[] inorder, int inLeft, int inRight){
            //终止条件
            if(preRight < preLeft || inRight < inLeft) return null;
            TreeNode root = new TreeNode(preorder[preLeft]);//新建节点
            //搜索左右子树分界点
            int inMid = inLeft;
            for(int i = inLeft; i <= inRight; i++){
                if(inorder[i] == preorder[preLeft]) inMid = i;
            }
            int preMid = preLeft + inMid - inLeft;
            //递归求左右子树,同样左闭右闭
            root.left = buildTree1(preorder, preLeft + 1, preMid, inorder, inLeft, inMid - 1);
            root.right = buildTree1(preorder, preMid + 1, preRight, inorder, inMid + 1, inRight);
            return root;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    114 二叉树展开为链表

    • 递归,前序遍历时使用数组保存节点顺序,最后统一修改节点左右指针
      • 时间复杂度O(n),空间复杂度O(n)
    class Solution {
        public void flatten(TreeNode root) {
            //递归
            List<TreeNode> preList = new ArrayList<>();
            //先序遍历
            preorder(root, preList);
            TreeNode pre = root;
            for(int i = 1; i < preList.size(); i++){
                TreeNode cur = preList.get(i);
                pre.left = null;
                pre.right = cur;
                pre = cur;
            }
        }
        private void preorder(TreeNode root, List<TreeNode> preList){
            if(root == null) return;
            preList.add(root);
            preorder(root.left, preList);
            preorder(root.right, preList);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    121 买卖股票的最佳时机

    • 贪心,之前做过,找到左边最小的买入价格
      • 时间复杂度O(n),空间复杂度O(1)
    class Solution {
        public int maxProfit(int[] prices) {
            //贪心
            int max = 0;
            int cur = 0;
            for(int i = 1; i < prices.length; i++){
                if(prices[i] < prices[cur]) cur = i;
                max = Math.max(max, prices[i] - prices[cur]);
            }
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    124 二叉树中的最大路径和

    • 递归,计算每个节点的最大贡献值,即该节点的值和左右节点的值的最大和,如果贡献为正,则记录最大路径和,否则不记录。
      • 时间复杂度O(n),空间复杂度O(n)
    class Solution {
        int max = Integer.MIN_VALUE;
        public int maxPathSum(TreeNode root) {
            //递归
            getMax(root);
            return max;
        }
        private int getMax(TreeNode root){
            if(root == null) return 0;
            //计算每个节点的最大贡献值,即该节点的值和左右节点的值的最大和
            //如果贡献为正,则记录最大路径和,否则不记录
            int left = Math.max(getMax(root.left), 0);
            int right = Math.max(getMax(root.right), 0);
            //当前节点贡献,计算贡献时可以同时选取左右孩子
            int cur = root.val + left + right;
            //更新
            max = Math.max(max, cur);
            //作为路径时不能同时选取左右孩子,只能选一条路
            return  root.val + Math.max(left, right);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    128 最长连续序列

    • 哈希表遍历数组并存储到set中,遍历set,若当前元素-1不在set中,说明当前元素为第一个,不断更新当前长度和最大长度;若在set中,说明当前元素不为第一个,跳过(由第一个元素进行遍历)。
      • 时间复杂度O(n),空间复杂度O(n)
    class Solution {
        public int longestConsecutive(int[] nums) {
            //哈希表
            Set<Integer> set = new HashSet<>();
            //遍历数组并存储到set中
            for(int num : nums){
                set.add(num);
            }
            //遍历set
            int max = 0;
            for(int num : set){
                //若当前元素-1在set中,说明当前元素不为第一个,跳过(由第一个元素进行遍历)
                if(set.contains(num - 1)) continue;
                //若当前元素-1不在set中,说明当前元素为第一个,不断更新当前长度和最大长度
                int cur = 0;
                while(set.contains(num)){
                    cur++;
                    num++;
                }
                max = Math.max(max, cur);
            }
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    136 只出现一次的数字

    • 遍历异或运算,同剑指JZ56-I
      • 时间复杂度O(n),空间复杂度O(1)
    class Solution {
        public int singleNumber(int[] nums) {
            int res = 0;
            for(int num : nums){
                res ^= num;
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    139 单词拆分

    • 完全背包,之前做过,可以多次使用,遍历字符串,判断当前位置之前的字符串是否能够拼接,因此同时遍历当前字符串的分割位置。遍历顺序从小到大。
      • 时间复杂度O(n^2),空间复杂度O(n)
    class Solution {
        public boolean wordBreak(String s, List<String> 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(wordDict.contains(s.substring(j, i)) && dp[j]){
                        dp[i] = true;
                        break;
                    }
                }
            }
            return dp[s.length()];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    141 环形链表

    • 双指针,同142 环形链表II,判断是否有环以及环的入口。
      • 时间复杂度O(n),空间复杂度O(1)
    public class Solution {
        public boolean hasCycle(ListNode head) {
            //双指针
            ListNode fast = head;
            ListNode slow =head;
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                if(fast == slow) return true;
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    Llama2-Chinese项目:2.1-Atom-7B预训练
    4.5 使用Go Modules自定义模块
    不同路径的数目
    ITX-3568JQ四核ITX工业级主板
    【算法设计zxd】第5章分治法
    Redis 分布式锁 @Klock 注解详解及使用教程
    Redis高可用实战之Replication
    Pulsar Meetup 深圳 2024 大咖推荐
    面试题------线程池的拒绝策略
    字符串相加
  • 原文地址:https://blog.csdn.net/Kiwi_fruit/article/details/125752105