LeetCode 第 205 场周赛 (暴力、哈希表、贪心+滑动窗口、贪心+并查集(最小生成树))

1576. 替换所有的问号

class Solution {
    
    
public:
    string modifyString(string s) {
    
    
        int len = s.size();
        for(int i=0;i<len;i++){
    
    
            if(s[i]=='?'){
    
    
                for(char c='a';c<='z';c++){
    
    
                    if(i==0){
    
    
                        if(c!=s[i+1]){
    
    
                            s[i] = c;
                            break;
                        }
                    }else if(i==len-1){
    
    
                        if(c!=s[i-1]){
    
    
                            s[i] = c;
                            break;
                        }
                    }else if(c!=s[i-1] && c!=s[i+1]){
    
    
                        s[i]=c;
                        break;
                    }
                }
            }
        }
        return s;
    }
};

1577. 数的平方等于两数乘积的方法数
用哈希表预存一个数组中两两乘积出现的次数。
然后在另一个数组进行遍历累积答案。

#define ll long long 
class Solution {
    
    
public:
    int numTriplets(vector<int>& a1, vector<int>& a2) {
    
    
        return helper(a1,a2)+helper(a2,a1);
    }
    int helper(const vector<int>& a1,const vector<int>& a2){
    
    
        unordered_map<ll,int> mp;
        int sum = 0;
        for(int i=0;i<a2.size();i++){
    
    
            for(int j=i+1;j<a2.size();j++){
    
    
                mp[(ll)a2[i]*a2[j]]++;
            }
        }
        for(int i=0;i<a1.size();i++){
    
    
            sum += mp[(ll)a1[i]*a1[i]];
        }
        return sum;
    }
};

1578. 避免重复字母的最小删除成本

  • 贪心
    遍历所有的连续的段,找出这一段代价和,以及这一段的最大代价,那个最大代价的字符不删,其余都删掉。
class Solution {
    
    
public:
    int minCost(string s, vector<int>& cost) {
    
    
        int l = 0,r = 0,mmax = 0,sum = 0,n=s.size();
        while(l<n){
    
    
            r = l;
            int cnt = 0;
            while(r<n && s[r]==s[l]){
    
    
                cnt += cost[r];
                mmax = max(mmax,cost[r]);
                r++;
            }
            sum += cnt - mmax;
            mmax = 0;
            l = r;
        }
        return sum;
    }
};
  • 动态规划

除了要记录某一段的花费值,为了进行状态转移,所以状态的维度还要多上某一段删除操作之后的最后一个字符。

  • 状态: d p [ i ] [ j ] dp[i][j] dp[i][j]表示前缀 [ 0 , i ] [0,i] [0,i]在进行删除操作称为合法字符串之后最后一个字母为 j j j的最小花费。
  • DP方程:
    • 当前的字符删去: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + c o s t [ i ] ( 0 ≤ j ≤ 26 ) dp[i][j]= dp[i-1][j]+cost[i](0≤j≤26) dp[i][j]=dp[i1][j]+cost[i]0j26
    • 当前的字符不删去: d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i − 1 ] [ k ] ) ( k ! = j ) dp[i][j]=min(dp[i][j],dp[i-1][k])(k!=j) dp[i][j]=min(dp[i][j],dp[i1][k])(k!=j)
class Solution {
    
    
public:
    int minCost(string s, vector<int>& cost) {
    
    
        int n = s.size(), INF = 1e9;
        vector<vector<int>> f(n+1,vector<int>(27,INF));
        f[0][s[0]-'a'] = 0, f[0][26] = cost[0];
        for(int i=1;i<n;i++){
    
    
            for(int j=0;j<27;j++) f[i][j] = f[i-1][j]+cost[i];
            int j = s[i]-'a';
            for(int k=0;k<27;k++){
    
    
                if(k!=j) f[i][j] = min(f[i][j],f[i-1][k]);
            }
        }     
        int ans = INF;
        for(int i=0;i<27;i++) ans = min(ans,f[n-1][i]);
        return ans; 
    }
};

1579. 保证图可完全遍历

因为要删去最多的边还要是无向图连通,实际上就是两个人的最小生成树(边权为1)。
一个贪心策略(此题的关键):
优先选取类型三的边,换句说,先让类型3的边去建树(如果冗余就不要)。
为什么?
反证法:考虑A、B两点,如果它们既可以用一条3号边去连接,亦可以用1号边、2号边(或者更多)去分别保证两个人的树的连通,那么后者的情况一定不优于前者!

class Solution {
    
    
    struct UF{
    
    
        int f[100100], cnt = 0; //cnt变量记录加入的边
        UF(){
    
    
            for(int i=1;i<=100000;i++) f[i] = i;
        }
        int find(int x){
    
    
            return x==f[x]?x:f[x] = find(f[x]);
        }
        bool merge(int x,int y){
    
    
            int fx = find(x);
            int fy = find(y);
            if(fx==fy) return 0;
            f[fx] = fy;
            cnt++;
            return 1;   
        }
    };
public:

    int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
    
    
        int ans = 0;
        UF alice,bob;
        for(auto &e:edges){
    
    
            if(e[0]==3){
    
    
                bool f1 = alice.merge(e[1],e[2]);
                bool f2 = bob.merge(e[1],e[2]);
                if(!f1 && !f2) ans++;               
            }
        }
        for(auto &e:edges){
    
    
            if(e[0]==1){
    
    
                if(!alice.merge(e[1],e[2])) ans++;
            }else if(e[0]==2){
    
    
                if(!bob.merge(e[1],e[2])) ans++;
            }
        }
        if(alice.cnt<n-1 || bob.cnt<n-1) return -1;
        return ans;
    }       
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/108447099
今日推荐