LeetCode——Weekly Contest 313

LeetCode周赛第313场记录

2427. 公因子的数目

这道题是让找出两个整数a,b之间的公因子数目,解决思路非常简单,就是找出两个数字中较小的一个数字,逐个遍历统计符合要求的数字个数即可。思路很简单,完整代码如下:

int commonFactors(int a, int b) 
{
    int Min = min(a,b);
    int Ans = 0;
    for(int i = 1 ; i <= Min ; ++i)
        if((a % i == 0) && (b % i == 0))
            Ans++;
    return Ans;
}

2428. 沙漏的最大总和

在这里插入图片描述
这道题首先给出了一个沙漏形状的定义,然后让我们找出最大沙漏的总和。
首先考虑如何计算一个沙漏,其实很简单,就是一个完整的 3 × 3 3 \times 3 3×3的矩形方块减去两个小块即可。

所以我首先写出了计算沙漏形状总和的函数:calculateSum,然后直接在整个网格grid中遍历求最大值即可,思路也很简单,完整代码如下:

// (i,j) is the left upper point
int calculateSum(vector<vector<int>>& grid, int i, int j, int m, int n)
{
    int Ans = 0;
    if(i + 2 < m && j + 2 < n)  // legal
    {
        for(int k = 0 ; k < 3 ; ++k)
            for(int l = 0 ; l < 3 ; ++l)
                Ans += grid[i + k][j + l];
        
        Ans -= grid[i + 1][j];
        Ans -= grid[i + 1][j + 2];
    }
    return Ans; // 0 means not legal
}

class Solution {
public:
    int maxSum(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int Ans = 0;
        for(int i = 0 ; i < m ; ++i)
            for(int j = 0 ; j < n ; ++j)
                Ans = max(Ans, calculateSum(grid, i, j, m, n));
        
        return Ans;
    }
};

2429. 最小 XOR

在这里插入图片描述
这道题开始有些难度了,一方面这个数字中的1的数量和num2保持一致,又要要求它和num1异或的结果最小。这道题基本思路是贪心+字符串模拟,贪心之处在于这道题不需要非常复杂的技巧,只需要从最简单的位运算入手,分类讨论即可。

首先要引入两个工具函数,bitCount和bitLength,它们的作用和实现如下:

1.bitCount:计数一个数字的二进制表示中中有多少个1

	int bitCount(int num)
    {
        int Ans = 0;
        while(num)
        {
            if(num % 2)
                ++Ans; 
            num >>= 1;
        }
        return Ans;
    }

2.bitLength:计数一个数字需要多少个二进制位来表达

    int bitLength(int num)
    {
        int Ans = 0;
        while(num)
        {
            ++Ans;
            num >>= 1;
        }
        return Ans;
    }

在上述两个工具函数的帮助下,针对这个问题,可以分如下几种情况来讨论:
1.如果num1的二进制长度还没有num2二进制表示中1的数量多(BitLength1 < BitCount2),那么这个时候我们只需要将num2中已有的1全部聚集在较低位上即可

2.如果num1和num2的二进制表示中1的数量一样多(BitCount1 = BitCount2),那么这个时候与num1抑或最小的数字x一定是num1本身,直接返回之即可

3.如果num1的二进制表示中1的数量比num2少(BitCount1 < BitCount2),那么这个时候只需要将数字num1中从低位开始的0挨个置为1即可,因为我们得保证XOR之后数字尽可能小,所以应该首先将多出来的1匀在低位上。

4.如果num1的二进制表示中1的数量比num2多(BitCount1 > BitCount2),那么这个时候只需要将数字num1中从低位开始的1挨个置为0即可,因为我们要保证num2的那些1中和掉num1中较高位上的1,所以只能先牺牲一部分留在低位上的1。

综上所述,完整的代码如下:

class Solution {
    int bitCount(int num)
    {
        int Ans = 0;
        while(num)
        {
            if(num % 2)
                ++Ans; 
            num >>= 1;
        }
        return Ans;
    }

    int bitLength(int num)
    {
        int Ans = 0;
        while(num)
        {
            ++Ans;
            num >>= 1;
        }
        return Ans;
    }

    int binaryStrToNum(string s)
    {
        int Ans = 0;
        int Size = s.size();
        for(int i = 0 ; i < Size ; ++i)
        {
            Ans = Ans << 1;
            Ans += s[i] - '0';
        }
        return Ans;
    }

    string numToBinaryStr(int num)
    {
        string Ans = "";
        while(num)
        {
            Ans.push_back(static_cast<char>(num % 2) + '0');
            num >>= 1;
        }
        reverse(Ans.begin(), Ans.end());
        return Ans;
    }

public:
    int minimizeXor(int num1, int num2) {
        int BitCount1 = bitCount(num1);
        int BitLength1 = bitLength(num1);
        int BitCount2 = bitCount(num2);

        if(BitCount2 >= BitLength1)
            return (1 << BitCount2) - 1;
        
        if(BitCount1 == BitCount2)
            return num1;
       
        string NumStr = numToBinaryStr(num1);
        int Size = NumStr.size();
        if(BitCount1 < BitCount2)
        {
            int Diff = BitCount2 - BitCount1;
            for(int i = Size - 1 ; i >= 0 && Diff > 0 ; --i)
                if(NumStr[i] == '0')
                {
                    NumStr[i] = '1';
                    --Diff;
                }
        }
            
        else if(BitCount1 > BitCount2)
        {
            int Diff = BitCount1 - BitCount2;
            for(int i = Size - 1 ; i >= 0 && Diff > 0 ; --i)
                if(NumStr[i] == '1')
                {
                    NumStr[i] = '0';
                    --Diff;
                }
        }
        return binaryStrToNum(NumStr);
    }
};

这道题如果使用位运算的技巧的话,可以比较省代码量,但是思维难度较高,如果用字符串模拟的话,就比较耗费代码量(如上所示)。

2430. 对字母串可执行的最大删除数

在这里插入图片描述
CopyRight:灵茶山艾府
这道题最终要转化为一个最终公共前缀问题(线性DP),然后基于此去考虑最大删除次数。
这道题给出的AC代码如下, 题解链接在此,不再重复解释了,多多理解学习吧,我是小菜鸡捏(逃…)

class Solution {
public:
    int deleteString(string s) {
        int n = s.length();
        if (equal(s.begin() + 1, s.end(), s.begin())) // 特判全部相同的情况
            return n;
        int lcp[n + 1][n + 1]; // lcp[i][j] 表示 s[i:] 和 s[j:] 的最长公共前缀
        memset(lcp, 0, sizeof(lcp));
        for (int i = n - 1; i >= 0; --i)
            for (int j = n - 1; j > i; --j)
                if (s[i] == s[j])
                    lcp[i][j] = lcp[i + 1][j + 1] + 1;
        int f[n];
        memset(f, 0, sizeof(f));
        for (int i = n - 1; i >= 0; --i) {
            for (int j = 1; i + j * 2 <= n; ++j)
                if (lcp[i][i + j] >= j) // 说明 s[i:i+j] == s[i+j:i+j*2]
                    f[i] = max(f[i], f[i + j]);
            ++f[i];
        }
        return f[0];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值