LeetCode刷题 day2

目录

    • 1.等和矩阵分割
    • [2. 错误的集合](#2. 错误的集合)
    • [3. 图片平滑器](#3. 图片平滑器)
    • [4. 二叉树中第二小的节点](#4. 二叉树中第二小的节点)

1.等和矩阵分割

给你一个由正整数组成的 m x n 矩阵 grid。你的任务是判断是否可以通过 一条水平或一条垂直分割线 将矩阵分割成两部分,使得:

分割后形成的每个部分都是非空的。

两个部分中所有元素的和相等 。

如果存在这样的分割,返回 true;否则,返回 false
思路

求出矩阵所有元素和,计算每行每列元素和,若总和不为偶数,直接返回false,再判断前k行(列)和是否等于一半总和

java 复制代码
class Solution {
    public boolean canPartitionGrid(int[][] grid) {
        long sum = 0;
        int m = grid.length, n = grid[0].length;
        long[] cols = new long[n];//列和
        long[] rows = new long[m];//行和
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                cols[j]+=grid[i][j];
                rows[i]+=grid[i][j];
                sum += grid[i][j];
            }
        }
        if(sum%2!=0){
            return false;
        }
        sum>>=1;
        long rowSum=0;
        for(int i=0;i<m;i++){
            rowSum+=rows[i];
            if(rowSum==sum){
                return true;
            }
        }
        long colSum=0;
        for(int i=0;i<n;i++){
            colSum += cols[i];
            if(colSum==sum){
                return true;
            }
        }
        return false;
    }
}

时间复杂度: O(n*m) 计算总和所需时间为大头
空间复杂度: O(max(n,m)),行和和列和的数组最大值

2. 错误的集合

集合 s 包含从1到n的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了该集合发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:

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

输出:[2,3]
示例 2:

输入:nums = [1,1]

输出:[1,2]
思路

巧妙的位运算

n个整数中有一个数字复制了另一个数字,则这两个数字一个出现两次,一个出现零次。将这n个数字与[1,n]这n个数字共2n个数字放一起,这两个数字一个出现三次,一个出现一次,其他数字出现偶数次,通过异或运算可知,最后结果为这两个数字异或值,找到最低位为1的位置,lowBit=xor&(-xor),再将lowBit与这2n个数字异或,得到的两个数为num1,num2,这两个数一个必为要求的两个数,再遍历一遍数组分出这两个数即可

java 复制代码
class Solution {
    public int[] findErrorNums(int[] nums) {
        //首先得到异或结果
        int xor = 0;
        int n = nums.length;
        for(int num:nums){
            xor^=num;
        }
        for(int i=1;i<=n;i++){
            xor^=i;
        }
        //找到元素最低不同位
        int lowBit = xor&(-xor);//可以找到最低位1
        //将2n个元素分为两组
        int nums1 = 0,nums2=0;
        for(int num:nums){
            if((num&lowBit)!=0){
                nums1^=num;
            }else{
                nums2^=num;
            }
        }
        for(int i=1;i<=n;i++){
            if((i&lowBit)!=0){
                nums1^=i;
            }else{
                nums2^=i;
            }
        }
        //再遍历一遍数组找到x和y
        for(int num:nums){
            if(nums1==num){
                return new int[]{nums1,nums2};
            }
        }
        return new int[]{nums2,nums1};
    }
}

时间复杂度: O(n) 遍历数组需要O(n)
空间复杂度: O(1)

3. 图片平滑器

图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。

每个单元格的 平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即,需要计算蓝色平滑器中 9 个单元格的平均值)。

如果一个单元格周围存在单元格缺失的情况,则计算平均灰度时不考虑缺失的单元格(即,需要计算红色平滑器中 4 个单元格的平均值)。
示例 1:

输入:img = [[1,1,1],[1,0,1],[1,1,1]]

输出:[[0, 0, 0],[0, 0, 0], [0, 0, 0]]

解释:

对于点 (0,0), (0,2), (2,0), (2,2): 平均(3/4) = 平均(0.75) = 0

对于点 (0,1), (1,0), (1,2), (2,1): 平均(5/6) = 平均(0.83333333) = 0

对于点 (1,1): 平均(8/9) = 平均(0.88888889) = 0

思路

以img[i][j]为中心的九宫格和可以看成是partSum[i+1][j+1]+partSum[i-2][j-2]-partSum[i-2][j]-partSum[i][j-2],其中,partSum是以img[i][j]为右边界和下边界的累加和,其他边界条件单独判断一下即可

java 复制代码
class Solution {
    public int[][] imageSmoother(int[][] img) {
        int m=img.length,n=img[0].length;
        int[][] partSum = new int[m][n];
        partSum[0][0] = img[0][0];
        for(int i=1;i<m;i++){
            partSum[i][0] = partSum[i-1][0]+img[i][0];
        }
        for(int i=1;i<n;i++){
            partSum[0][i] = partSum[0][i-1]+img[0][i];
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                partSum[i][j]= partSum[i-1][j]+partSum[i][j-1]-partSum[i-1][j-1]+img[i][j];
            }
        }
        int[][] res = new int[m][n];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                //分情况讨论
                int h_x = i+1==m?i:i+1;
                int h_y = j+1==n?j:j+1;
                if(i-2<0&&j-2<0){
                    res[i][j] = partSum[h_x][h_y]/((h_x+1)*(h_y+1));
                }else if(i-2<0){
                    res[i][j] = (partSum[h_x][h_y]-partSum[h_x][j-2])/((h_x+1)*(h_y-j+2));
                }else if(j-2<0){
                    res[i][j] = (partSum[h_x][h_y]-partSum[i-2][h_y])/((h_y+1)*(h_x-i+2));
                }else{
                    res[i][j] = (partSum[h_x][h_y]+partSum[i-2][j-2]-partSum[h_x][j-2]-partSum[i-2][h_y])/((h_x-i+2)*(h_y-j+2));
                }
            }
        }
        return res;
    }
}

时间复杂度: O(nm)
空间复杂度: O(n
m)

4. 二叉树中第二小的节点

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。

更正式地说,即 root.val = min(root.left.val, root.right.val) 总成立。

给出这样的一个二叉树,你需要输出所有节点中的 第二小的值 。

如果第二小的值不存在的话,输出 -1 。
思路

发现该二叉树的性质是根节点为全局最小值,则递归遍历,找到全局最小的大于该最小值的值即可,并且每个子树都满足该性质,所以找到就返回,即找到左右子树上大于该节点的值即返回

java 复制代码
class Solution {
    int min;
    public int findSecondMinimumValue(TreeNode root) {
        min = root.val;
        return dfs(root);
    }
    private int dfs(TreeNode node){
        if(node==null){
            return -1;
        }
        if(node.val>min){
            return node.val;
        }
        int val1 = dfs(node.left);
        int val2 = dfs(node.right);
        return val1==-1?val2:(val2==-1?val1:Math.min(val1,val2));
    }
}

时间复杂度: O(n)
空间复杂度: O(logn) 取决于树的深度

相关推荐
Tisfy2 小时前
LeetCode 2946.循环移位后的矩阵相似检查:模拟(左即是右)
算法·leetcode·矩阵·题解
zhishidi2 小时前
推荐算法核心课:基于距离的相似度度量
算法·机器学习·推荐算法
Trouvaille ~2 小时前
【优选算法篇】队列与宽度优先搜索(BFS)——层层递进的视野
c++·算法·leetcode·青少年编程·面试·蓝桥杯·宽度优先
hanlin032 小时前
动态规划专练:力扣第509、70、746题
算法·leetcode·动态规划
CoderIsArt2 小时前
shor算法
算法·量子计算
m0_743890512 小时前
3月27日 模拟题
算法
watersink3 小时前
自然科学专技类C类-题型策略
职场和发展
北顾笙9803 小时前
day09-数据结构力扣
数据结构·算法·leetcode
旖-旎3 小时前
位运算(判断字符是否唯一)(1)
c++·算法·leetcode·位运算