LeetCode 第 35 场双周赛(前缀和、差分+贪心、哈希表+同余、模拟+拓扑排序)

1588. 所有奇数长度子数组的和

class Solution {
    
    
public:
    int sumOddLengthSubarrays(vector<int>& a) {
    
    
        int n = a.size();
        int ans = 0;
        vector<int> s(n,0);
        s[0] = a[0];
        for(int i=1;i<n;i++) s[i] = s[i-1]+a[i];
        for(int len = 1;len<=n;len+=2){
    
    
            for(int i=0;i+len<=n;i++){
    
    
                int ss = s[i+len-1];
                if(i) ss -= s[i-1];
                ans += ss;
            }
        }
        return ans;
    }
};

1589. 所有排列中的最大和
贪心很容易想到,主要是如何统计每个位置的出现的次数。
比赛时想歪了,用了线段树的区间修改懒标记

  • 差分维护区间
    如果想要给 [ l , r ] [l,r] [l,r]都加上一个增量 d d d,对于差分数组而言其实只有两项发生了变化, s [ l ] = s [ l ] + d ( s [ l ] = a [ l ] − a [ l − 1 ] ) s[l]=s[l]+d(s[l]=a[l]-a[l-1]) s[l]=s[l]+ds[l]=a[l]a[l1], s [ r + 1 ] = s [ r + 1 ] − d s[r+1]=s[r+1]-d s[r+1]=s[r+1]d

所以用差分来维护每次修改的开销是 O ( n ) O(n) O(n)的。

如何还原,差分数组的前缀和就是原数组

class Solution {
    
    
public:
    int mod = 1e9+7;
    int s[100010] = {
    
    0},a[100010] = {
    
    0};
    int maxSumRangeQuery(vector<int>& nums, vector<vector<int>>& requests) {
    
    
        int n = nums.size();
        for(vector<int>& v:requests){
    
    
            s[v[0]] ++;
            s[v[1]+1] --;
        }
        a[0] = s[0];
        for(int i=1;i<n;i++){
    
    
            a[i] = a[i-1]+s[i];
        }
        sort(nums.begin(),nums.end());
        sort(a,a+n);
        long long ans = 0;
        for(int i=0;i<n;i++){
    
    
            ans = (ans+nums[i]*a[i])%mod;
        }
        return ans;
    }
};

1590. 使数组和能被 P 整除

  • 如果 s u m % p = t a r sum \% p = tar sum%p=tar;
  • 那么 被删除的子数组 [l,r] 的和应该在模 p p p意义下等于 t a r tar tar
  • s [ r ] ≡ t a r + s [ l − 1 ] ( m o d    p s[r] \equiv tar + s[l-1] (\mod p s[r]tar+s[l1](modp
  • s [ l − 1 ] ≡ s [ r ] − t a r ( m o d    p ) s[l-1] \equiv s[r]-tar (\mod p) s[l1]s[r]tarmodp)
class Solution {
    
    
public:
    typedef long long ll;
    int minSubarray(vector<int>& nums, int p) {
    
    
        ll sum = 0;
        for(int x:nums) sum += x;
        int tar = sum%p;
        if(tar==0) return 0;
        unordered_map<int,int> mp;
        mp[0] = -1;
        ll s = 0;
        int ans = 1e9, n = nums.size();
        for(int i=0;i<n;i++){
    
    
            s = (s+nums[i])%p;
            if(mp.count( ((s-tar)%p+p)%p )){
    
    
                ans = min(ans,i-mp[ ((s-tar)%p+p)%p ]);
            } 
            mp[s] = i; // 因为求最短
        }
        if(ans==1e9 || ans==n) return -1;
        return ans;
    }
};

1591. 奇怪的打印机 II

  • 这题拓扑排序的思路很容易想到,然后终点就是实现,也就是要模拟这个拓扑排序的过程了。

  • 拓扑排序的过程中最核心的一点就是把入度为0的点入队,然后拓展出更多的点。
    如何模拟这个过程?

    • 首先如何确定一个矩形呢,记录一下某种颜色的左边界、右边界、上边界、下边界,然后在这个矩形里的数字必须是这种颜色或者是通配符(将某个颜色去掉之后,这个点其实就是任意匹配了,将通配符记为0)
    • 先把可以去除的矩形入队,然后依次出队,出队后,所在的位置都改成通配符,然后检查是否可以有更多的矩形块产生(相当于就是新的入度为0的点),如果有,入队。
    • 反复进行,直至结束。完成标志就是矩阵全都更改为通陪符。
class Solution {
    
    
    struct Rectangle{
    
    
        int id;
        int x1 = 100,y1 = 100,x2 = 0,y2 = 0;
        Rectangle(int id = 0):id(id){
    
    }

        void update(int x,int y){
    
    
            x1 = min(x1,x);
            x2 = max(x2,x);
            y1 = min(y1,y);
            y2 = max(y2,y);
        }
    }rs[65];
    
public:
    bool vis[65] = {
    
    0};
    vector<int> colors;
    vector<vector<int>> g;
    int m,n;
    bool isPrintable(vector<vector<int>>& targetGrid) {
    
    
        g = targetGrid;
        m = g.size();
        n = g[0].size();
        for(int i=0;i<m;i++){
    
    
            for(int j=0;j<n;j++){
    
    
                if(vis[g[i][j]]==0){
    
    
                    vis[ g[i][j] ] = 1;
                    colors.push_back( g[i][j] );
                    rs[ g[i][j] ] = Rectangle(g[i][j]);
                }
                rs[ g[i][j] ].update(i,j);
            }
        }

        memset(vis,0,sizeof(vis));
        queue<int> q;
        for(int c:colors){
    
    
            if(check(rs[c]) && !vis[c]){
    
    
                q.push(c);
                vis[c] = 1;
            }
        }

        while(q.size()){
    
    
            int c = q.front();
            q.pop();
            updateGrid(rs[c]);
            for(int c:colors){
    
    
                if(!vis[c] && check(rs[c])){
    
    
                    q.push(c);
                    vis[c] = 1;
                }
            }
        }
        return finish();
    }
    
    bool finish(){
    
    
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(g[i][j]) return false;
        return true;
    }
    
    bool check(const Rectangle& rec){
    
    
        for(int x=rec.x1;x<=rec.x2;x++)
            for(int y=rec.y1;y<=rec.y2;y++)
                if(g[x][y]!=rec.id && g[x][y]!=0) return false;

        return true;
    }
    
    void updateGrid(const Rectangle& rec){
    
    
        for(int x=rec.x1;x<=rec.x2;x++)
            for(int y=rec.y1;y<=rec.y2;y++) g[x][y] = 0;    
    }  
};

猜你喜欢

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