月度归档: 2022年6月

LeetCode刷题【剑指 Offer 07】重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

示例 1:

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

示例 2:

Input: preorder = [-1], inorder = [-1]
Output: [-1]

限制:

0 <= 节点个数 <= 5000

注意:本题与主站 105 题重复:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ Related Topics

  • 数组
  • 哈希表
  • 分治
  • 二叉树

👍 830👎 0

学二叉树入门必做题

学二叉树入门必做

关键信息

  1. 前序遍历的第一个值为根节点
  2. 到中序遍历中找到根节点所在位置,前面的部分为左子节点内容,后面的部分为右子节点内容
  3. 得到的左右子节点的长度,重新回到前序遍历的结果中,根节点后面对应左子节点长度的部分为左子树的前序遍历,后面一部分为右子树的前序遍历
  4. 拿到了步骤3和2的左子树的中序和前序遍历结果 重新做步骤1,右子树部分也同样走步骤1

前中后序遍历

左右两个子节点的顺序不变都是先左子节点,后右子节点,区别就在于根节点是先遍历,还是中间,还是最后

这分别就是前中后序遍历

相关特性

现有如图这个一对前序遍历和中序遍历结果

根据相关特效,前序遍历的第一个就是根节点,所以我们知道了,根节点为3

又中序遍历中左侧只有一个,所以左子树只有一个节点9,右子树部分暂时不知道只知道剩下部分为右侧的前序和中序遍历结果,二叉树如下

再接下来,我们把右子树部分的按照同样的逻辑处理

我们知道了右子树的根节点为20,20的左子树只有一个节点15,右子树只有一个节点7

这样我们就重新构建完成了整棵二叉树

代码

class Solution {
    int[] preorder;
    int[] inorder;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        this.inorder = inorder;
        int len = preorder.length-1;
        return buildTree(0,len,0,len);
    }

    public TreeNode buildTree( int preL, int preR, int inL, int inR){
        if (preL > preR){
            return null;
        }
        TreeNode node = new TreeNode(preorder[preL]);
        int len = 0;
        for (int i = inL; i <= inR; i++) {
            if (inorder[i] == preorder[preL]){
                len = i - inL;
            }
        }
        node.left = buildTree(preL+1,preL+len,inL,inL+len-1);
        node.right = buildTree(preL+len+1,preR,inL+len+1,inR);
        return node;
    }
}

LeetCode刷题【238】除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

不要使用除法,且在 O(n) 时间复杂度内完成此题。

 

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

 

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内

 

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)

Related Topics
  • 数组
  • 前缀和

  • 👍 1190
  • 👎 0
  • 前缀和(积)

    class Solution {
        public int[] productExceptSelf(int[] nums) {
            int len = nums.length;
            int[] arrL = new int[len];
            int[] arrR = new int[len];
            arrL[0] = 1;
            arrR[len-1] = 1;
            for (int i = 1; i < nums.length; i++) {
                arrL[i] = nums[i-1] * arrL[i-1];
                int rIdx = len-i-1;
                arrR[rIdx] = nums[rIdx+1] * arrR[rIdx+1];
            }
    
            int[] res = new int[len];
            for (int i = 0; i < res.length; i++) {
                res[i] = arrL[i] * arrR[i];
            }
            return res;
        }
    }

    缩减下

    class Solution {
        public int[] productExceptSelf(int[] nums) {
            int[] res = new int[nums.length];
            res[0] = 1;
            for (int i = 1; i < nums.length; i++) {
                res[i] = res[i-1] * nums[i-1];
            }
            int preR =  nums[nums.length-1];
            for (int r = nums.length-2; r >= 0; r--) {
                res[r] *= preR;
                preR *= nums[r];
            }
            return res;
        }
    }

    LeetCode刷题【剑指 Offer 68 – I】二叉搜索树的最近公共祖先

    给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

    例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

     

    示例 1:

    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
    输出: 6 
    解释: 节点 2 和节点 8 的最近公共祖先是 6。
    

    示例 2:

    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
    输出: 2
    解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

     

    说明:

    • 所有节点的值都是唯一的。
    • p、q 为不同节点且均存在于给定的二叉搜索树中。

    注意:本题与主站 235 题相同:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

    Related Topics
    • 深度优先搜索
    • 二叉搜索树
    • 二叉树

  • 👍 239
  • 👎 0
  • 二叉搜索树特性

    1. 递归

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (p.val > q.val){
                return lowestCommonAncestor(root,q,p);
            }
            if (root.val == p.val || root.val == q.val){
                return root;
            }
            if (root.val > p.val && root.val > q.val){
                return lowestCommonAncestor(root.left,p,q);
            }
            if (root.val < p.val && root.val < q.val){
                return lowestCommonAncestor(root.right,p,q);
            }
            return root;
        }
    }

    2. 指针

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (p.val > q.val){
                return lowestCommonAncestor(root,q,p);
            }
            TreeNode cur = root;
            while ((cur.val > p.val && cur.val >q.val) || (cur.val < p.val && cur.val <q.val)){
                if (cur.val > p.val && cur.val >q.val){
                    cur = cur.left;
                }
                if (cur.val < p.val && cur.val <q.val){
                    cur = cur.right;
                }
            }
            return cur;
        }
    }

    比较简单,不做过多分析了

    LeetCode刷题【剑指 Offer 55 – II】平衡二叉树

    输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

     

    示例 1:

    给定二叉树 [3,9,20,null,null,15,7]

        3
       / \
      9  20
        /  \
       15   7

    返回 true

    示例 2:

    给定二叉树 [1,2,2,3,3,null,null,4,4]

           1
          / \
         2   2
        / \
       3   3
      / \
     4   4
    

    返回 false

     

    限制:

    • 0 <= 树的结点个数 <= 10000

    注意:本题与主站 110 题相同:https://leetcode-cn.com/problems/balanced-binary-tree/

     

    Related Topics
    • 深度优先搜索
    • 二叉树

  • 👍 288
  • 👎 0
  • DFS深搜模板套用

    解题思路

    1. 借助深搜模板,计算每层对应高度
    2. 判断每个节点的左右子节点高度相差是否小于2
    3. 如果不小于2则不是平衡二叉树

    代码

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
    
        boolean isBalanced = true;
        public boolean isBalanced(TreeNode root) {
            dfs(root,0);
            return isBalanced;
        }
    
        public int dfs(TreeNode node, int dep){
            if (!isBalanced || null == node){
                return dep;
            }
            dep++;
            int leftDep = dfs(node.left,dep);
            int rightDep = dfs(node.right,dep);
            if (Math.abs(leftDep-rightDep )< 2){
                return Math.max(leftDep,rightDep);
            }
            isBalanced = false;
            return Math.max(leftDep,rightDep);
        }
    }

    LeetCode刷题【面试题40】最小的k个数

    输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

     

    示例 1:

    输入:arr = [3,2,1], k = 2
    输出:[1,2] 或者 [2,1]
    

    示例 2:

    输入:arr = [0,1,2,1], k = 1
    输出:[0]

     

    限制:

    • 0 <= k <= arr.length <= 10000
    • 0 <= arr[i] <= 10000
    Related Topics
    • 数组
    • 分治
    • 快速选择
    • 排序
    • 堆(优先队列)

  • 👍 450
  • 👎 0
  • 堆排序

    解题思路

    此处撰写解题思路

    代码

    class Solution {
        public int[] getLeastNumbers(int[] arr, int k) {
            if (k == 0){
                return new int[0];
            }
            PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o2 - o1;
                }
            });
            for (int i : arr) {
                if (queue.size() < k){
                    queue.offer(i);
                }else if(i < queue.peek()){
                    queue.poll();
                    queue.offer(i);
                }
            }
            int[] res = new int[k];
            for (int i = 0; i < res.length; i++) {
                res[i] = queue.poll();
            }
            return res;
        }
    }

    LeetCode刷题【1816】截断句子

    句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

    • 例如,"Hello World""HELLO""hello world hello world" 都是句子。

    给你一个句子 s​​​​​​ 和一个整数 k​​​​​​ ,请你将 s​​ 截断 ​,​​​使截断后的句子仅含 k​​​​​​ 个单词。返回 截断 s​​​​​​ 后得到的句子

     

    示例 1:

    输入:s = "Hello how are you Contestant", k = 4
    输出:"Hello how are you"
    解释:
    s 中的单词为 ["Hello", "how" "are", "you", "Contestant"]
    前 4 个单词为 ["Hello", "how", "are", "you"]
    因此,应当返回 "Hello how are you"
    

    示例 2:

    输入:s = "What is the solution to this problem", k = 4
    输出:"What is the solution"
    解释:
    s 中的单词为 ["What", "is" "the", "solution", "to", "this", "problem"]
    前 4 个单词为 ["What", "is", "the", "solution"]
    因此,应当返回 "What is the solution"

    示例 3:

    输入:s = "chopper is not a tanuki", k = 5
    输出:"chopper is not a tanuki"
    

     

    提示:

    • 1 <= s.length <= 500
    • k 的取值范围是 [1,  s 中单词的数目]
    • s 仅由大小写英文字母和空格组成
    • s 中的单词之间由单个空格隔开
    • 不存在前导或尾随空格
    Related Topics
    • 数组
    • 字符串

  • 👍 57
  • 👎 0
  • 空格判断、字符复制

    1. 简单,就复制字符
    2. 字符复制完了加一个空格
    3. 计数,小于k
    4. 最后会多复制一个空格最后要截掉

    代码

    class Solution {
        public String truncateSentence(String s, int k) {
            char[] arr = new char[501];
            int cnt = 0;
            int idx = 0;
            int arrIdx = -1;
            while (cnt < k && idx < s.length()){
                if (s.charAt(idx) == ' '){
                    idx++;
                    continue;
                }
                while (idx < s.length() && s.charAt(idx) != ' ' ){
                    arr[++arrIdx] = s.charAt(idx++);
                }
                arr[++arrIdx] = ' ';
                cnt++;
            }
            char[] arr2 = new char[arrIdx];
            System.arraycopy(arr,0,arr2,0,arrIdx);
            return new String(arr2);
        }
    }

    其实题目给了限制条件了

     1 <= s.length <= 500 
     k 的取值范围是 [1, s 中单词的数目] 
     s 仅由大小写英文字母和空格组成 
     s 中的单词之间由单个空格隔开 
     不存在前导或尾随空格 

    所以可以更简单点,直接判断遇到的空格的个数就可以了

    代码

    class Solution {
        public String truncateSentence(String s, int k) {
            char[] arr = s.toCharArray();
            int cnt = 0;
            int idx = -1;
            while (cnt < k && ++idx < s.length()){
                if (arr[idx] == ' '){
                    cnt++;
                }
            }
            char[] arr2 = new char[idx];
            System.arraycopy(arr,0,arr2,0,idx);
            return new String(arr2);
        }
    }

    LeetCode刷题【383】赎金信

    给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

    如果可以,返回 true ;否则返回 false

    magazine 中的每个字符只能在 ransomNote 中使用一次。

     

    示例 1:

    输入:ransomNote = "a", magazine = "b"
    输出:false
    

    示例 2:

    输入:ransomNote = "aa", magazine = "ab"
    输出:false
    

    示例 3:

    输入:ransomNote = "aa", magazine = "aab"
    输出:true
    

     

    提示:

    • 1 <= ransomNote.length, magazine.length <= 105
    • ransomNotemagazine 由小写英文字母组成
    Related Topics
    • 哈希表
    • 字符串
    • 计数

  • 👍 363
  • 👎 0
  • 哈希统计

    class Solution {
        public boolean canConstruct(String ransomNote, String magazine) {
            int[] arr = new int[26];
            for (int i = 0; i < magazine.length(); i++) {
                arr[magazine.charAt(i)-'a']++;
            }
            for (int i = 0; i < ransomNote.length(); i++) {
                arr[ransomNote.charAt(i)-'a']--;
                if (arr[ransomNote.charAt(i)-'a'] < 0 ){
                    return false;
                }
            }
            return true;
        }
    }