加载中...

leetcode双周赛149 T4(DP + 输出具体方案)

题目链接:problem

\(f[i][j]\): 将\(str[i]\)变为字符\(j\),将\(str[i到n]\)变为合法字符串,需要的最小操作次数。

\(nxt[i][j]\):将\(str[i]\)变为字符\(j\)的所有方案中,最优方案转移过来的字符。其中:

  1. \(nxt[i][j]==j\)\(f[i][j]\)\(f[i+1][j]\) 转移而来(意味着最优方案下\(str[i]==j,且str[i+1]==j\)
  2. \(nxt[i][j]==k,k!=j\)\(f[i][j]\)\(f[i+3][k]\) 转移而来(意味着最优方案下\(str[i]==str[i+1]==str[i+2]==j,str[i+3]==k\)

\(minj[i]\):将\(str[i到n]\)变为合法字符串的最优方案中,\(str[i]\)应该变为的字符。

\(ans = f[0][minj[0]]\)方案对应的字符串

\(trans\)

\[f[i][j] = min(f[i + 1][j] + cost[str[i]->j], \min_{k=0}^{25}f[i + 3][k] + cost[str[i]->j] + cost[str[i+1]->j] + cost[str[i+2]->j]) \]

注意当后者的\(k==j\)时,前者的最优方案一定不会比后者的最优方案更劣。因此可以直接枚举(\(continue\)掉也可以)。

按照该转移式\(dp\)后,最小代价已知。再根据\(minj[0]\)\(nxt\)数组来还原最优方案对应的字符串,根据\(nxt\)数组的定义来还原即可。

复杂度:\(O(n*26*26)\)。还可以优化掉一个\(26\):每次计算完一轮\(f[i][]\)时,新开一个\(minf[i]\)来保存\(f[i][0到25]\)的最小值,这样就省去了最内层\(26\)的枚举。

代码:

class Solution {

#define inf 0x3f3f3f3f
int f[50010][26];
int nxt[50010][26]; 
int minj[50010];

public:
    string minCostGoodCaption(string str) {
        int n = str.size();
        if(n < 3){
            return "";
        }

        for(int i = n - 1; i >= 0; i--){
            int mn = inf;
            for(int j = 0; j < 26; j++){
                int res1 = f[i + 1][j] + abs(str[i] - 'a' - j);
                int res2 = inf;
                
                if(i <= n - 6){
                     for(int k = 0; k < 26; k++){
                        res2 = min(res2, f[i + 3][k] + abs(str[i] - 'a' - j) + abs(str[i + 1] - 'a' - j) 
                                         + abs(str[i + 2] - 'a' - j));
                    }
                }
               
                if(res2 < res1 || (res2 == res1 && minj[i + 3] < j)){
                    nxt[i][j] = minj[i + 3];                    
                } else{
                    nxt[i][j] = j;
                }
                
                f[i][j] = min(res1, res2);
                
                if(f[i][j] < mn){ // 保证了构造出的最优方案下的字符串的字典序最小
                    mn = f[i][j];
                    minj[i] = j;
                }
            }
        }

        string ans(n, 0);
        int i = 0, j = minj[0];
        while(i < n){
            ans[i] = 'a' + j;
            int k = nxt[i][j];
            if(k == j){
                i++;
            }else{
                ans[i + 2] = ans[i + 1] = ans[i];
                i += 3;
                j = k;
            }
        }
        return ans;
    }
};
posted @ 2025-02-04 08:34  jxs123  阅读(14)  评论(0)    收藏  举报