沙漏的最大总和&&最小 XOR

96 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

[6193. 沙漏的最大总和]

leetcode.cn/problems/ma…

image-20221002152514288


nm = 150150 约等于2w多个数据 因此可以枚举下每一种情况的7个位置,计算一下总和,然后更新最大值, 并且这里的所有数都是非负数 ->答案非负数!

先枚举参考点!! -> 可以设中心点为我们的参考点 中心点的行范围是:[1,数组行数-2] 列范围是:[1,数组列数-2]

然后计算以(i,j)为中心的参考点的沙漏型的总和

image-20221002154434586


累加沙漏中的元素的和

image-20221002154835846

class Solution {
public:
    int maxSum(vector<vector<int>>& grid) {
        int row = grid.size();//行
        int col = grid[0].size();//列
        int ans = 0;
        for(int i = 1;i<row-1;i++)
        {
            for(int j = 1;j<col-1;j++)
            {
                //(i,j)就是沙漏的中心点
                //计算当前以(i,j)为中心点的沙漏的和
                int sum = grid[i][j];
                for(int k = j-1;k<=j+1;k++) 
                {
                    sum += grid[i-1][k] + grid[i+1][k];
                }
                //更新答案
                ans = max(ans,sum);
            }
        }
        return ans;
    }
};

[6194. 最小 XOR]

leetcode.cn/problems/mi…

image-20221002152545189


1)因为数据范围是10^9 二进制表示最多有30位, 2^30 >= 10亿

2)首先要求一下num2里面二进制1的数量,这样就直到答案x里面1的数量

3)由于异或可以看成是:无进位相加, 所以我们可以发现:

  • 如果num1这一位本来是1,我们把x的1放到这一位,那么会让num1减去一个数
  • 如果num1这一位本来是0,我们把x的1放到这一位,那么会让num1加上一个数

image-20221002161559401

如果这一位越高,加的数/减的数越大, 现在放的1的数量是唯一确定的(等于num2的置位数),假设为k, 要求放了k个1之后,使num1的结果最小


贪心:

x的置位数和num2的置位数相同,意味着x的二进制序列中有k个 1,我们需要合理的分配这k个1,为了让异或和最小,这些1应当从高位到低位匹配 num中的 1, 如果匹配完num1中所有的1,还有多余的1可以分配,那么就从低位到高位把0改为1 (加上2^比特位所在的位置)

  • 先从高位选择1,后从低位选择0
  • 首先统计num2二进制中1出现的个数, 将这些1分配出去, 因为是要得到一个最小的 x^num1, 所以我们需要对num1的二进制位的权值进行排序, 使用贪心思想尽可能地找到最小的 x^num1, 如此就可以找出x了.

res = a^x ==> x = a^res

class Solution {
public:
    int minimizeXor(int num1, int num2) {
        int cnt = 0;
        //1.计算num2中比特位1的个数(置位数)
        while(num2)
        {
            num2&=(num2-1);
            cnt++;
        }
        //求法2  while(num2)  cnt+= b&1,b>>=1;
      
        int res = 0;
        //先从高位往低位选择置1,要保证还有1可以置
        for(int i = 29;i>=0 && cnt>0;i--)
        {
            if((num1 >> i)&1)//这一位是1
            {
                res -= (1<<i);
                cnt--;
            }
        }
        //从低位往高位置1,要保证还有1可以置
        for(int i = 0;i<30&&cnt>0;i++)
        {
            if(((num1 >> i)&1) == 0)//这一位是0
            {
                res += (1<<i); 
                cnt--;
            }
        }
​
        //其中num1+res就是x^num1异或的答案ans   如何得到x呢? x = ans^num1
        return (num1+res)^num1;   
    }
};

x 最低位上的 1 变为 0 : x = x&(x-1)

x 最低位上的 0 变为 1: x = x | (x+1)