LeetCode 第 34 场双周赛 (矩阵、乘法原理计数、双指针、DP)

5491. 矩阵对角线元素的和

class Solution {
    
    
public:
    int diagonalSum(vector<vector<int>>& mat) {
    
    
        int sum = 0, n = mat.size();
        for(int i=0;i<n;i++){
    
    
            sum += mat[i][i];
            if(i!=n-i-1) sum += mat[i][n-i-1];
        }
        return sum;
    }
};

5492. 分割字符串的方案数
几种特殊情况

  • 全为0,返回(n-2)*(n-1)/2;
  • 1的个数不为3的倍数,返回0;
  • 1的个数为3的倍数。乘法原理,计算三段字符串中的中间的0的个数。
class Solution {
    
    
public:
    int mod = 1e9+7;
    int numWays(string s) {
    
    
        int num = 0, len = s.size();
        for(char c:s) if(c=='1') num++;
        
        if(num%3) return 0;
        if(num==0){
    
    
            if(len<3) return 0;
            else return (long long)(len-2)%mod*(len-1)/2%mod;
        }

        int t = num/3, cnt = 0;
        int x1,x2,x3,x4;
        for(int i=0;i<len;i++){
    
    
            if(s[i]=='1'){
    
    
                ++ cnt;
                if(cnt==t) x1 = i;
                if(cnt==t+1) x2 = i;
                if(cnt==2*t) x3 = i;                
                if(cnt==2*t+1) x4 = i;
            }
        }
        return (long long)(x2-x1)%mod*(x4-x3)%mod;
    }
};

别人的更加简洁的代码。

typedef long long ll;
class Solution {
    
    
public:
    int a[100002], P=1000000007;
    int numWays(string s) {
    
    
        int n = s.size(),x=0,y=0;
        for(int i = 0; i < n; i++){
    
    
            a[i+1] = a[i] + (s[i] == '1'); // a[i]表示i之前1的个数
        }
        if(a[n] == 0) return (ll)(n-1)*(n-2)/2%P; // a[n]为1总数,如果没有1则C(2,n-1)
        if(a[n]%3) return 0;  // 有1但不满足均分3组
        for(int i = 0; i <= n; i++){
    
    
            if(a[i] == a[n]/3) x++;     // 统计第一个分界线可以插入的槽位
            if(a[i] == a[n]/3*2) y++;   // 统计第二个分解线可以插入的槽位
        }
        return (ll)x*y%P;
        
    }
};

5493. 删除最短的子数组使剩余数组有序
思路:
首先求出左右两端的升序端。
然后答案可以是只删除两端,取较小值。
最后问题就处理成了,两个有序段,去除第一段的后半部分,去除第二段的前半部分,拼接成一个尽可能长的段。
双指针处理。

class Solution {
    
    
public:
    int findLengthOfShortestSubarray(vector<int>& a) {
    
    
        int n = a.size(), l = 1, r = n-1;
        while(l<n && a[l]>=a[l-1]) l++;
        while(r>0 && a[r]>=a[r-1]) r--;
        // [0,l-1]  [r,n] 都是升序的
        if(l==n) return 0;
        int ans = min(n-l,r), i = 0, j = r;
        while(i<l && j<n){
    
    
            // [i+1,j-1]是要删去的
            if(a[i]<=a[j]){
    
    
                ans = min(ans,j-i-1);
                i++;
            }else j++;
        }
        return ans;
    }
};
/*
[1,2,4,6,8,9,10]
[5,7,9,10,12]
*/

5494. 统计所有可行路径
DP,记忆化搜索实现。

  • 状态: d p [ i ] [ f ] dp[i][f] dp[i][f]到达 i i i的时候,油量为 f f f的方案数。
  • 状态转移:对所有可以转移的下一个点进行转移, d p [ i ] [ f ] = ∑ { d p [ j ] [ f − a b s ( a [ i ] − a [ j ] ) ] } dp[i][f]=\sum \{ dp[j][f-abs(a[i]-a[j])]\} dp[i][f]={ dp[j][fabs(a[i]a[j])]}
    注意,如果达到某个点的时候,那个点就已经是终点,那么方案数要初始化为1。
class Solution {
    
    
public:
    int dp[110][210];
    int mod = 1e9+7, e , n;
    int countRoutes(vector<int>& a, int s, int e, int f) {
    
    
        this->e = e, n = a.size();
        memset(dp,-1,sizeof(dp));
        return dfs(s,f,a);
    }
    int dfs(int i,int f,const vector<int>& a){
    
    
        if(dp[i][f]!=-1) return dp[i][f];
        int &res = dp[i][f];
        res = 0;
        if(i==e) res = 1;
        for(int j=0;j<n;j++){
    
    
            if(j!=i && abs(a[i]-a[j])<=f){
    
    
                res = (res+dfs(j,f-abs(a[i]-a[j]),a) )%mod;
            }
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/108438923