目录
-
- 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(nm)
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) 取决于树的深度