【LeetCode】第 92 场双周赛题解

136 阅读1分钟

6249. 分割圆的最少切割次数

圆内一个 有效切割 ,符合以下二者之一:

  • 该切割是两个端点在圆上的线段,且该线段经过圆心。
  • 该切割是一端在圆心另一端在圆上的线段。

一些有效和无效的切割如下图所示。

给你一个整数 n ,请你返回将圆切割成相等的 n 等分的 最少 切割次数。

 

示例 1:

输入: n = 4
输出: 2
解释:
上图展示了切割圆 2 次,得到四等分。

示例 2:

输入: n = 3
输出: 3
解释:
最少需要切割 3 次,将圆切成三等分。
少于 3 次切割无法将圆切成大小相等面积相同的 3 等分。
同时可以观察到,第一次切割无法将圆切割开。

 

提示:

  • 1 <= n <= 100

注意:n=1n=1 的情况

class Solution {
public:
    int numberOfCuts(int n) {
        if(n == 1){
            return 0;
        }
        return n%2? n : n/2;
    }
};

6277. 行和列中一和零的差值

给你一个下标从 0 开始的 m x n 二进制矩阵 grid 。

我们按照如下过程,定义一个下标从 0 开始的 m x n 差值矩阵 diff :

  • 令第 i 行一的数目为 onesRowi 。
  • 令第 j 列一的数目为 onesColj 。
  • 令第 i 行零的数目为 zerosRowi 。
  • 令第 j 列零的数目为 zerosColj 。
  • diff[i][j] = onesRowi + onesColj - zerosRowi - zerosColj

请你返回差值矩阵 **diff 。

 

示例 1:

输入: grid = [[0,1,1],[1,0,1],[0,0,1]]
输出: [[0,0,4],[0,0,4],[-2,-2,2]]
解释:
- diff[0][0] = onesRow0 + onesCol0 - zerosRow0 - zerosCol0 = 2 + 1 - 1 - 2 = 0 
- diff[0][1] = onesRow0 + onesCol1 - zerosRow0 - zerosCol1 = 2 + 1 - 1 - 2 = 0 
- diff[0][2] = onesRow0 + onesCol2 - zerosRow0 - zerosCol2 = 2 + 3 - 1 - 0 = 4 
- diff[1][0] = onesRow1 + onesCol0 - zerosRow1 - zerosCol0 = 2 + 1 - 1 - 2 = 0 
- diff[1][1] = onesRow1 + onesCol1 - zerosRow1 - zerosCol1 = 2 + 1 - 1 - 2 = 0 
- diff[1][2] = onesRow1 + onesCol2 - zerosRow1 - zerosCol2 = 2 + 3 - 1 - 0 = 4 
- diff[2][0] = onesRow2 + onesCol0 - zerosRow2 - zerosCol0 = 1 + 1 - 2 - 2 = -2
- diff[2][1] = onesRow2 + onesCol1 - zerosRow2 - zerosCol1 = 1 + 1 - 2 - 2 = -2
- diff[2][2] = onesRow2 + onesCol2 - zerosRow2 - zerosCol2 = 1 + 3 - 2 - 0 = 2

示例 2:

输入: grid = [[1,1,1],[1,1,1]]
输出: [[5,5,5],[5,5,5]]
解释:
- diff[0][0] = onesRow0 + onesCol0 - zerosRow0 - zerosCol0 = 3 + 2 - 0 - 0 = 5
- diff[0][1] = onesRow0 + onesCol1 - zerosRow0 - zerosCol1 = 3 + 2 - 0 - 0 = 5
- diff[0][2] = onesRow0 + onesCol2 - zerosRow0 - zerosCol2 = 3 + 2 - 0 - 0 = 5
- diff[1][0] = onesRow1 + onesCol0 - zerosRow1 - zerosCol0 = 3 + 2 - 0 - 0 = 5
- diff[1][1] = onesRow1 + onesCol1 - zerosRow1 - zerosCol1 = 3 + 2 - 0 - 0 = 5
- diff[1][2] = onesRow1 + onesCol2 - zerosRow1 - zerosCol2 = 3 + 2 - 0 - 0 = 5

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 105
  • 1 <= m * n <= 105
  • grid[i][j] 要么是 0 ,要么是 1 。

题解:使用4个数组分别存储行列 0,1的数量。

class Solution {
public:
    vector<vector<int>> onesMinusZeros(vector<vector<int>>& g) {
        int n = g.size(), m = g[0].size();
        vector<vector<int>> res(n, vector<int>(m, 0));
        vector<int> o1(n, 0),z1(n, 0);
        vector<int> o2(m, 0),z2(m, 0);
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(g[i][j]){
                    o1[i]++;
                    o2[j]++;
                }else{
                    z1[i]++;
                    z2[j]++;
                }
            }
        }
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                res[i][j] = (long long)o1[i]+o2[j]-((long long)z1[i]+z2[j]);
            }
        }
        return res;
    }
};

6250. 商店的最少代价

给你一个顾客访问商店的日志,用一个下标从 0 开始且只包含字符 'N' 和 'Y' 的字符串 customers 表示:

  • 如果第 i 个字符是 'Y' ,它表示第 i 小时有顾客到达。
  • 如果第 i 个字符是 'N' ,它表示第 i 小时没有顾客到达。

如果商店在第 j 小时关门(0 <= j <= n),代价按如下方式计算:

  • 在开门期间,如果某一个小时没有顾客到达,代价增加 1 。
  • 在关门期间,如果某一个小时有顾客到达,代价增加 1 。

请你返回在确保代价 最小 的前提下,商店的 最早 关门时间。

注意,商店在第 j 小时关门表示在第 j 小时以及之后商店处于关门状态。

 

示例 1:

输入: customers = "YYNY"
输出: 2
解释:
- 第 0 小时关门,总共 1+1+0+1 = 3 代价。
- 第 1 小时关门,总共 0+1+0+1 = 2 代价。
- 第 2 小时关门,总共 0+0+0+1 = 1 代价。
- 第 3 小时关门,总共 0+0+1+1 = 2 代价。
- 第 4 小时关门,总共 0+0+1+0 = 1 代价。
在第 2 或第 4 小时关门代价都最小。由于第 2 小时更早,所以最优关门时间是 2 。

示例 2:

输入: customers = "NNNNN"
输出: 0
解释: 最优关门时间是 0 ,因为自始至终没有顾客到达。

示例 3:

输入: customers = "YYYY"
输出: 4
解释: 最优关门时间是 4 ,因为每一小时均有顾客到达。

 

提示:

  • 1 <= customers.length <= 105
  • customers 只包含字符 'Y' 和 'N' 。

题解:前缀和,前缀和统计 "Y" 和 "N" 的数量,枚举位置,假设 p 为最佳位置,统计 p位置之前的"N"的个数和p位置及p之后的"Y"的数量,取最小值,以及最小位置。

class Solution {
public:
    int bestClosingTime(string c) {
        int n = c.size();
        vector<int> cntn(n+1), cnty(n+1);
        for(int i=1; i<=n; i++){
            if(c[i-1] == 'Y'){
                cnty[i] = cnty[i-1]+1;
                cntn[i] = cntn[i-1];
            }else{
                cntn[i] = cntn[i-1]+1;
                cnty[i] = cnty[i-1];
            }
        }
        int tot = INT_MAX;
        int res = n;
        for(int i=0; i<=n; i++){
            int t = cntn[i] + (cnty[n] - cnty[i]);
            if(t < tot){
                tot = t;
                res = i;
            }
        }
        return res;
    }
};

6251. 统计回文子序列数目

给你数字字符串 s ,请你返回 s 中长度为 5 的 回文子序列 数目。由于答案可能很大,请你将答案对 109 + 7 取余 后返回。

提示:

  • 如果一个字符串从前往后和从后往前读相同,那么它是 回文字符串 。
  • 子序列是一个字符串中删除若干个字符后,不改变字符顺序,剩余字符构成的字符串。

 

示例 1:

输入: s = "103301"
输出: 2
解释:
总共有 6 长度为 5 的子序列:"10330""10331""10301""10301""13301""03301" 。
它们中有两个(都是 "10301")是回文的。

示例 2:

输入: s = "0000000"
输出: 21
解释: 所有 21 个长度为 5 的子序列都是 "00000" ,都是回文的。

示例 3:

输入: s = "9999900000"
输出: 2
解释: 仅有的两个回文子序列是 "99999""00000"

 

提示:

  • 1 <= s.length <= 104
  • s 只包含数字字符。

题解:前缀和+枚举,由于题目给出的长度是5的回文数,例如 i位置,前面是 "xy" 那么后面是 "yx",题目给出 s 字符串全是数字,所以 x或者y 只能为0~9。

typedef long long LL;
const int N = 10010;
// l数组含义从 0 ~i 位置 x,y的数量,
// r数组含义从n~i+1 位置 y,x的数量,
int l[N][10][10], r[N][10][10]; 
class Solution {
public:
    int countPalindromes(string s) {
        int n = s.size();
        int cnt[10] = {0};
        for(int i=1; i<=n; i++){
            for(int j=0; j<10; j++){
                for(int k=0; k<10; k++){
                    l[i][j][k] = l[i-1][j][k];
                }
            }
            int y = s[i-1]-'0';
            for(int j=0; j<10; j++){
                l[i][j][y] += cnt[j];
            }
            cnt[y]++;
        }
        for(int i=0; i<10; i++){
            for(int j=0; j<10; j++){
                r[n+1][i][j] = 0;
            }
        }
        memset(cnt, 0, sizeof cnt);
        for(int i=n; i>0; i--){
            for(int j=0; j<10; j++){
                for(int k=0; k<10; k++){
                    r[i][j][k] = r[i+1][j][k];
                }
            }
            int y = s[i-1]-'0';
            for(int j=0; j<10; j++){
                r[i][y][j] +=cnt[j]; 
            }
            cnt[y]++;
        }
        int res = 0;
        int mod = 1e9+7;
        for(int i=1; i<=n; i++){
            for(int j=0; j<10; j++){
                for(int k=0; k<10; k++){
                    res = (res +(LL)l[i-1][j][k]*r[i+1][k][j])%mod;
                }
            }
        }
        return res;
    }
};