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

题目链接:problem

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

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

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

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

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

trans

f[i][j]=min(f[i+1][j]+cost[str[i]>j],mink=025f[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(n2626)。还可以优化掉一个26:每次计算完一轮f[i][]时,新开一个minf[i]来保存f[i][025]的最小值,这样就省去了最内层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 @   jxs123  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示
主题色彩