leetcode4

617.给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:


输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]
示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]
 

提示:

两棵树中的节点数目在范围 [0, 2000] 内
-104 <= Node.val <= 104

第一反应是递归

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1==null&&root2==null){
            return null;
        }
        
        if(root1==null){return root2;}
        if(root2==null){return root1;}
        //重叠当前节点
        TreeNode temp=new TreeNode(root1.val+root2.val);
        //重叠当前节点的左子树
        temp.left=mergeTrees(root1.left,root2.left);
        //重叠当前节点的右子树
        temp.right=mergeTrees(root1.right,root2.right);
        return temp;
    }
}

 答案为深度优先搜索和广度优先搜索,深度优先搜索同上。

1.广度优先搜索-三个队列。。

class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if (t1 == null) {
            return t2;
        }
        if (t2 == null) {
            return t1;
        }
        TreeNode merged = new TreeNode(t1.val + t2.val);
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        Queue<TreeNode> queue1 = new LinkedList<TreeNode>();
        Queue<TreeNode> queue2 = new LinkedList<TreeNode>();
        queue.offer(merged);
        queue1.offer(t1);
        queue2.offer(t2);
        while (!queue1.isEmpty() && !queue2.isEmpty()) {
            TreeNode node = queue.poll(), node1 = queue1.poll(), node2 = queue2.poll();
            TreeNode left1 = node1.left, left2 = node2.left, right1 = node1.right, right2 = node2.right;
            if (left1 != null || left2 != null) {
                if (left1 != null && left2 != null) {
                    TreeNode left = new TreeNode(left1.val + left2.val);
                    node.left = left;
                    queue.offer(left);
                    queue1.offer(left1);
                    queue2.offer(left2);
                } else if (left1 != null) {
                    node.left = left1;
                } else if (left2 != null) {
                    node.left = left2;
                }
            }
            if (right1 != null || right2 != null) {
                if (right1 != null && right2 != null) {
                    TreeNode right = new TreeNode(right1.val + right2.val);
                    node.right = right;
                    queue.offer(right);
                    queue1.offer(right1);
                    queue2.offer(right2);
                } else if (right1 != null) {
                    node.right = right1;
                } else {
                    node.right = right2;
                }
            }
        }
        return merged;
    }
}

98.给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
 

示例 1:


输入:root = [2,1,3]
输出:true
示例 2:


输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
 

提示:

树中节点数目范围在[1, 104] 内
-231 <= Node.val <= 231 - 1

第一反应又是递归-但是没写出来,想不到重新写一个和比较当前节点的左子树和当前节点值这方法。

!!!错了很多次

class Solution {
    public boolean isValidBST(TreeNode root) {
        
      return isVBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
    }
    public boolean isVBST(TreeNode root,long left,long right){
        if(root==null){
            return true;
        }
        if(root.val<=left||root.val>=right){
            return false;
        }
        return isVBST(root.left,left,root.val)&&isVBST(root.right,root.val,right);
    }
}

  中序遍历法:

不要轻易使用全局变量,尤其是static修饰。不然有可能出错。

class Solution {
    static List<Integer> list=new ArrayList<>();//去掉static就没有这个问题了
    public boolean isValidBST(TreeNode root) {
      //中序遍历树
      infixOrder(root);  
      System.out.print(isASC(list)); 
      return isASC(list);
    }
    public static void infixOrder(TreeNode root){
        if(root==null){
            return;
        }
        if(root.left!=null){
            infixOrder(root.left);
        }
        list.add(root.val);
        if(root.right!=null){
            infixOrder(root.right);
        }
    }
    //判断数组是否升序
    public boolean isASC(List<Integer> list){
        for(int i=0;i<list.size();i++){
            if(i+1<list.size()&&list.get(i)>=list.get(i+1)){
                return false;
            }
        }
        return true;
    }
}

class Solution {
    
    public boolean isValidBST(TreeNode root) {
      //中序遍历树
      List<Integer> list=infixOrder(root,new ArrayList<Integer>());
      return isASC(list);
    }
    public static List<Integer> infixOrder(TreeNode root,List<Integer> list){
        

        if(root==null){
            return null;
        }
        if(root.left!=null){
            infixOrder(root.left,list);
        }
        list.add(root.val);
        if(root.right!=null){
            infixOrder(root.right,list);
        }
        return list;
    }
    //判断数组是否升序
    public boolean isASC(List<Integer> list){
        for(int i=0;i<list.size();i++){
            if(i+1<list.size()&&list.get(i)>=list.get(i+1)){
                return false;
            }
        }
        return true;
    }
}

338.给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

示例 1:

输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:

输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
 

提示:

0 <= n <= 105
 

进阶:

很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?
你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )

class Solution {
    public int[] countBits(int n) {
        int[] res=new int[n+1];
        for(int i=0;i<=n;i++){
            res[i]=countBit(i);
        }
        return res;
    }
    public int countBit(int num){
        //统计一个数字的二进制中1的个数
        //1.先转二进制
        String temp=Integer.toBinaryString(num);
        char[] c=temp.toCharArray();
        //2.统计c中1的个数
        int count=0;
        for(int i=0;i<c.length;i++){
            if(c[i]=='1'){
                count++;
            }
        }
        return count;
    }
}

 被官方解法全方面虐

1.Brain Kernighan算法

本质就是疯狂与来统计1的个数:

对于任意整数 x,令 x=x&(x-1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x变成 0,则操作次数即为 x 的「一比特数」。

class Solution {
    public int[] countBits(int n) {
        int[] res=new int[n+1];
        for(int i=0;i<=n;i++){
            res[i]=countBit(i);
        }
        return res;
    }
    public int countBit(int num){
        //统计一个数字的二进制中1的个数
        int count=0;
        while(num>0){
            num=num&(num-1);
            count++;
        }
        return count;
    }
}

2.动态规划-最高有效位

3.动态规划-最低有效位

4.动态规划-最低设置位

这答案根本不想看啊,老和尚念经似的。。什么破玩意,不看了。

5.奇偶 和那劳什子最低有效位一样

class Solution {
    public int[] countBits(int n) {
        int[] res=new int[n+1];
        //奇偶搞一哈
        //1.奇数的1的个数=比他小的偶数的1的个数+1;
        //2.偶数的1的个数=偶数/2的1的个数
        for(int i=0;i<=n;i++){
            if(i%2==0){
                res[i]=res[i/2];
            }else{
                res[i]=res[i-1]+1;
            }
        }
        return res;
    }
}
class Solution {
    public int[] countBits(int n) {
        int[] res=new int[n+1];
        //奇偶搞一哈
        //1.奇数的1的个数=比他小的偶数的1的个数+1;
        //2.偶数的1的个数=偶数/2的1的个数
        for(int i=0;i<=n;i++){
            res[i]=res[i/2]+i%2;
        }
        return res;
    }
}

124.路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:


输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6
示例 2:


输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
 

提示:

树中节点数目范围是 [1, 3 * 104]
-1000 <= Node.val <= 1000

class Solution {
    //写一个全局变量计算路径值
    int path=Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        maxPath(root);
        return path;
    }
    public int maxPath(TreeNode root){
        if(root==null){
            return 0;
        }
        //左边告诉我左边的最大路径
        int left=Math.max(maxPath(root.left),0);
        //右边告诉我右边的最大路径
        int right=Math.max(maxPath(root.right),0);
        //我和左右一起
        int temp=root.val+left+right;
        //我目前最大的路径能不能大过我儿子,大过了就更新
        path=Math.max(temp,path);
        //这个节点的最大贡献值,往左往右或是停在原地
        return root.val+Math.max(left,right);
    }
}

 279.给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4
示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9
 
提示:

1 <= n <= 104

1.四平方和

class Solution {
    public int numSquares(int n) {
        if(isSquare(n)){return 1;}
        if(isFourSquare(n)){return 4;}
        if(isTwoSquare(n)){return 2;}
        return 3;
    }
    //判断一个数是不是完全平方数
    public boolean isSquare(int num){
        int a=(int)Math.sqrt(num);
        return a*a==num;
    }
    //判断一个数是不是由四个完全平方数的和
    public boolean isFourSquare(int num){
        while(num%4==0){
            num/=4;
        }
        return num%8==7;
    }
    //判断一个数是不是两个平方数的和
    public boolean isTwoSquare(int num){
        for(int i=0;i<Math.sqrt(num)+1;i++){
            int j=num-i*i;
            if(isSquare(j)){
                return true;
            }
        }
        return false;
    }
}

 2.动态规划-讨厌动态规划

3.背包算法

class Solution {
    public int numSquares(int n) {
        int res=n;
        int i=2;
            while(i*i<=n){
                int temp=n/(i*i);
                int temp1=n%(i*i);
                res=Math.min(res,temp+numSquares(temp1));
                i++;
            }
        
        return res;
    }
}

215.给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
 

提示:

1 <= k <= nums.length <= 104
-104 <= nums[i] <= 104

复习一下堆排序

class Solution {
    public int findKthLargest(int[] nums, int k) {
       //对重复元素的数组排序
       heapSort(nums);
       return nums[nums.length-k];
    }
    public void heapSort(int[] nums){
        //排成大顶堆
        for(int i=nums.length/2-1;i>=0;i--){
            adjustHeap(nums,i,nums.length);
        }
        //排完第一次
        for(int j=nums.length-1;j>0;j--){
            int temp=nums[j];
            nums[j]=nums[0];
            nums[0]=temp;
            adjustHeap(nums,0,j);
        }

    }
    public void adjustHeap(int[] nums,int i,int length){
        int temp=nums[i];
        for(int k=2*i+1;k<length;k=2*k+1){
            if(k+1<length&&nums[k]<nums[k+1]){
                k++;
            }
            if(nums[k]>temp){
                nums[i]=nums[k];
                i=k;
            }else{
                break;
            }
        }
        nums[i]=temp;
    }
}

 复习一下快速排序

class Solution {
    public int findKthLargest(int[] nums, int k) {
        //快排复习一下
        quickSort(nums,0,nums.length-1);
        for(int i=0;i<nums.length;i++){
            System.out.print(nums[i]);
        }
        return nums[nums.length-k];
    }
    public void quickSort(int[] nums,int left,int right){
        int l=left;
        int r=right;
        int piviot=nums[(l+r)/2];
        while(l<r){
            while(nums[l]<piviot){
                l++;
            }
            while(nums[r]>piviot){
                r--;
            }
            if(l>=r){
                break;
            }
            int temp=nums[l];
            nums[l]=nums[r];
            nums[r]=temp;
            if(nums[l]==piviot){
                r--;
            }
            if(nums[r]==piviot){
                l++;
            }
        }
        if(l==r){
            l++;
            r--;
        }
        if(left<r){
            quickSort(nums,left,r);
        }
        if(right>l){
            quickSort(nums,l,right);
        }
    }
}

发现上面两种写法仿佛都不如答案用的堆排序和快速排序。

优化:

1、注意到每次运行结束当前标杆的位置都是定下来的,只需要某次标杆恰好是倒数第k个下标时,就找到了答案,后面怎么排无人在意。

2、为排除极端案例,使用随机化的pivot。

晕眩了。。

42.给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 
示例 2:

输入:height = [4,2,0,3,2,5]
输出:9
 

提示:

n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

高低得给家人们表演一个暴力阴兵

直接一手超出时间限制。。

class Solution {
    public int trap(int[] height) {
        //类似俄罗斯方块
        //找到height中最大的数
        int max=0;
        int result=0;
        for(int i=0;i<height.length;i++){
            if(height[i]>max){
                max=height[i];
            }
        }
        for(int i=1;i<=max;i++){
            result+=square(height,i);
        }
        return result;
    }
    public int square(int[] height,int floor){
        int left=0;
        int right=height.length-1;
        int res=0;
        while(left<=height.length-1&&height[left]<floor){
            left++;
        }
        while(right>=0&&height[right]<floor){
            right--;
        }
        if(left==right){
            return 0;
        }
        //从left到right所有小于floor的数都要算一个面积
        for(int i=left;i<=right;i++){
            if(height[i]<floor){
                res++;
            }
        }
        return res;
    }
}

 538.给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
注意:本题和 1038: https://leetcode-cn.com/problems/binary-search-tree-to-greater-sum-tree/ 相同

示例 1:

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
示例 2:

输入:root = [0,null,1]
输出:[1,null,1]
示例 3:

输入:root = [1,0,2]
输出:[3,3,2]
示例 4:

输入:root = [3,2,4,1]
输出:[7,9,4,10]
 

提示:

树中的节点数介于 0 和 104 之间。
每个节点的值介于 -104 和 104 之间。
树中的所有值 互不相同 。
给定的树为二叉搜索树。

逆序中序遍历搞一哈;

 

class Solution {
    int res=0;
    public TreeNode convertBST(TreeNode root) {
        infixOrder(root);
        return root;
    }
    public void infixOrder(TreeNode root){
        if(root==null){
            return;
        }
        
         if(root.right!=null){
            infixOrder(root.right);
        }
        res+=root.val;
        root.val=res;
        if(root.left!=null){
            infixOrder(root.left);
        } 
    }
}

答案还有一种莫里斯遍历。

莫里斯遍历的核心思想是用空闲指针减少空间开销。

class Solution {
    int res=0;
    public TreeNode convertBST(TreeNode root) {
        TreeNode curr=root;
        while(curr!=null){
            if(curr.right==null){
                res+=curr.val;
                //System.out.print(res);
                curr.val=res;
                curr=curr.left;
            }else{
                TreeNode temp=curr.right;
                //找到最左边的那个
                while(temp.left!=null&&temp.left!=curr){
                    temp=temp.left;
                }
                //5指向4
                if(temp.left==null){
                    temp.left=curr;
                    curr=curr.right;
                }else{
                    //遍历结束了,得恢复
                    temp.left=null;
                    res+=curr.val;
                    curr.val=res;
                    curr=curr.left;
                }

            }
        }
        return root;
    }

}

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) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)。

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]=nums[i-1]*res[i-1];
       }
       int temp=1;
       //res[nums.length-1]不动
       for(int i=nums.length-1;i>0;i--){
           temp=nums[i]*temp;
           //System.out.print(temp+"\t");
            res[i-1]*=temp;
       }
       return res;
    }
}

 739.给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]
 

提示:

1 <= temperatures.length <= 105
30 <= temperatures[i] <= 100

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        //第一想法是双指针
        int[] res=new int[temperatures.length];
        for(int i=0;i<temperatures.length-1;i++){
            for(int j=i;j<temperatures.length;j++){
                if(temperatures[j]>temperatures[i]){
                    res[i]=j-i;
                    break;
                }
            }
        }
        return res;
    }
}

 题目解法单调栈,这个东西没学过。

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int length = temperatures.length;
        int[] ans = new int[length];
        //搞个栈
        Deque<Integer> stack=new LinkedList<>();
       for (int i = 0; i < length; i++) {
            int temp = temperatures[i];
            while(!stack.isEmpty()&&temp>temperatures[stack.peek()]){
                int k=stack.pop();
                ans[k]=i-k;
            }
            stack.push(i);
        }
        return ans;
    }
}

448.给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:

输入:nums = [1,1]
输出:[2]
 

提示:

n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> res=new ArrayList<>();
        int n=nums.length;
        for(int i=0;i<nums.length;i++){
           int k=(nums[i]-1)%n;
           nums[k]+=n;
        }
        for(int i=0;i<n;i++){
            System.out.print(nums[i]+"\t");
            if(nums[i]<=n){
                res.add(i+1);
            }
        }
        return res;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值