第 313 场周赛

98 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

6192. 公因子的数目

给你两个正整数 a 和 b ,返回 a 和 b 的  因子的数目。

如果 x 可以同时整除 a 和 b ,则认为 x 是 a 和 b 的一个 公因子 。

示例 1:

输入: a = 12, b = 6
输出: 4
解释: 126 的公因子是 1236

示例 2:

输入: a = 25, b = 30
输出: 2
解释: 2530 的公因子是 15

 

提示:

  • 1 <= a, b <= 1000
思路

范围不大,直接枚举

代码
class Solution {
public:
    int commonFactors(int a, int b) {
        int ans = 0;
        for(int i = 1; i <= min(a, b); i ++) {
            if (a % i == 0 && b % i == 0) ans ++;
        }
        return ans;
    }
};

6193. 沙漏的最大总和

给你一个大小为 m x n 的整数矩阵 grid 。

按以下形式将矩阵的一部分定义为一个 沙漏 :

返回沙漏中元素的 最大 总和。

注意: 沙漏无法旋转且必须整个包含在矩阵中。

 

示例 1:

输入: grid = [[6,2,1,3],[4,2,1,5],[9,2,8,7],[4,1,2,9]]
输出: 30
解释: 上图中的单元格表示元素总和最大的沙漏:6 + 2 + 1 + 2 + 9 + 2 + 8 = 30

示例 2:

输入: grid = [[1,2,3],[4,5,6],[7,8,9]]
输出: 35
解释: 上图中的单元格表示元素总和最大的沙漏:1 + 2 + 3 + 5 + 7 + 8 + 9 = 35

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 3 <= m, n <= 150
  • 0 <= grid[i][j] <= 106
思路

直接for 循环遍历每一个可以形成沙漏的形状即可

代码
class Solution {
public:
    int maxSum(vector<vector<int>>& grid) {
        int ans = 0;
        int n = grid.size();
        int m = grid.back().size();
        pair<int, int> fa[] = {
            {0, 0},
            {-1, 0}, {-1, -1}, {-1, 1},
            {1, 0}, {1, -1}, {1, 1}
        };
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                int res = 0, f = 1;
                for (auto v : fa) {
                    int x = i + v.first;
                    int y = j + v.second;
                    if (x < 0 || y < 0 || x >= n || y >= m) {
                        f = 0;
                        break;
                    }
                    res += grid[x][y];
                }
                if (!f) continue;
                ans = max(ans, res);
            }
        }
        
        return ans;
    }
};

6194. 最小 XOR

给你两个正整数 num1 和 num2 ,找出满足下述条件的整数 x :

  • x 的置位数和 num2 相同,且
  • x XOR num1 的值 最小

注意 XOR 是按位异或运算。

返回整数 **x 。题目保证,对于生成的测试用例, x 是 唯一确定 的。

整数的 置位数 是其二进制表示中 1 的数目。

 

示例 1:

输入: num1 = 3, num2 = 5
输出: 3
解释:
num1 和 num2 的二进制表示分别是 0011 和 0101 。
整数 3 的置位数与 num2 相同,且 3 XOR 3 = 0 是最小的。

示例 2:

输入: num1 = 1, num2 = 12
输出: 3
解释:
num1 和 num2 的二进制表示分别是 0001 和 1100 。
整数 3 的置位数与 num2 相同,且 3 XOR 1 = 2 是最小的。

 

提示:

  • 1 <= num1, num2 <= 109
思路

要求异或值最小 且 1的个数和num2相同

首先,我们从大到小去构造一个数,他1的位置和num1一样 这样可以保证异或最小

其次,若是num2的1的个数比num1多,那么我们从低位到高位再依次补齐即可

代码

class Solution {
public:
    int minimizeXor(int num1, int num2) {
        int cnt = 0;
        for (int i = 0; i < 31; i ++) cnt += (num2>>i&1);
        int ans = 0;
        for (int i = 30; i >= 0 && cnt; i --) {
            if (num1 >> i & 1) {
                ans |= 1 << i;
                cnt --;
            }
        }
        for (int i = 0; i < 31 && cnt; i ++) {
            if (ans >> i & 1) continue;
            cnt --;
            ans |= 1 << i;
        }
        return ans;
    }
};

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

给你一个仅由小写英文字母组成的字符串 s 。在一步操作中,你可以:

  • 删除 整个字符串 s ,或者
  • 对于满足 1 <= i <= s.length / 2 的任意 i ,如果 s 中的  i 个字母和接下来的 i 个字母 相等 ,删除  i 个字母。

例如,如果 s = "ababc" ,那么在一步操作中,你可以删除 s 的前两个字母得到 "abc" ,因为 s 的前两个字母和接下来的两个字母都等于 "ab" 。

返回删除 s 所需的最大操作数。

 

示例 1:

输入: s = "abcabcdabc"
输出: 2
解释:
- 删除前 3 个字母("abc"),因为它们和接下来 3 个字母相等。现在,s = "abcdabc"。
- 删除全部字母。
一共用了 2 步操作,所以返回 2 。可以证明 2 是所需的最大操作数。
注意,在第二步操作中无法再次删除 "abc" ,因为 "abc" 的下一次出现并不是位于接下来的 3 个字母。

示例 2:

输入: s = "aaabaab"
输出: 4
解释:
- 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "aabaab"。
- 删除前 3 个字母("aab"),因为它们和接下来 3 个字母相等。现在,s = "aab"。 
- 删除第一个字母("a"),因为它和接下来的字母相等。现在,s = "ab"。
- 删除全部字母。
一共用了 4 步操作,所以返回 4 。可以证明 4 是所需的最大操作数。

示例 3:

输入: s = "aaaaa"
输出: 5
解释: 在每一步操作中,都可以仅删除 s 的第一个字母。

 

提示:

  • 1 <= s.length <= 4000
  • s 仅由小写英文字母组成
思路

想法:类似于kmp

我们得先求出来当前值的最大前缀和后缀相等是多少

这样求有什么好处呢

若是当前值的最大前缀和后缀加起来刚好不多不少,中间没有其他数组偏移

那么,我们就可以知道这个值是可以删除的

这个是第一点

其次,我们得贪心的删除,为保证删除次数最大,我们每次一个尽可能的删除掉最大的一串

因为若是删除小的,后续可能用的时候就不能够用了

比如 aabaab, 我们可以删除a, 或者 aab, 我们发现,删除 a之和,结果不会变得更好

时间复杂度:总体最多循环 n 次,每次求kmp数组的时间复杂度是 n,计算最大删除时间复杂度是n

总体下来,时间复杂度是 n2n^2

可以通过

代码
class Solution {
public:
    int deleteString(string s) {
        int ans = 0;
        while (1) {
            string p = " " + s;
            vector<int> ne(p.size() + 2);
            int m = s.size();
            for (int i = 2, j = 0; i <= m; i ++ ) {
                while (j && p[i] != p[j + 1]) j = ne[j];
                if (p[i] == p[j + 1]) j ++ ;
                ne[i] = j;
            }
            int f = 0;
            for (int i = m; i >= 1; i --) {
                if (ne[i] * 2 == i) {
                    s = s.substr(ne[i]);
                    f = 1;
                    break;
                }
            }
            ans ++;
            if (f) continue;
            break;
        }
        return ans;
    }
};