LeetCode 秋葉收藏集

JustDreamer發表於2020-10-04

題目描述

題目連結
題意也比較好懂,就是說給你一個字串只含有r和y這兩種字元,每次操作可以翻轉一個字元,把r變成y或者把y變成r。問把整個字串翻轉成[r…y…r]的形式至少需要多少次?

題目分析

其實也比較好思考。考慮dp[i][j]表示[0,i]的字串全部處理好了並且第i個字元是狀態是j的情況,其實j只有三種選擇(r1,y,r2)這個r1和r2不是一種狀態,r1代表y還沒有出現,r2代表y已經出現過了。那麼轉移其實也顯而易見了:
(1)dp[i][0]的轉移
dp[i][0]的含義就是前i個都是r,因為這時y沒有出現過,那麼只需要考慮第i位是不是r就行了,不是就需要操作加1
dp[i][0]=dp[i-1][0]+(leaves[i]==y)
(2)dp[i][1]的轉移
其實這個轉移也很好推,dp[i][1]代表當前出現的是y這一段,那麼他就只有兩種可能,前邊出現過或者前邊沒有出現過,前邊出現過就是dp[i-1][1],沒有出現過就是dp[i-1][0].這兩個取個最小值即可。
dp[i][1]=min(dp[i-1][1],dp[i-1][0])+(leaves[i]==r)
(3)dp[i][2]的轉移
考慮此時的狀態就是出現過了ry,到第三個r了。那麼他也只有兩種轉移,要麼前邊已經出現過r,要麼從這當前開始出現r,如果是從當前出現r,說明前邊肯定是y。所以這裡的轉移就是:
dp[i][2]=min(dp[i-1[2],dp[i-1][1])+leaves[i]==y
這裡的坑就是不能從dp[i][0]直接轉移過來。
然後dp[leaves.size()-1][2]就是答案

程式碼

class Solution {
public:
    int minimumOperations(string leaves) {
        if (leaves.size() == 0)return 0;
        const int maxn = 1e5 + 10;
        int dp[maxn][3];
        dp[0][0] = (leaves[0] == 'r' ? 0 : 1);
        dp[0][1]= dp[0][2] = INT_MAX;
        dp[1][2] = INT_MAX;
        for (int i = 1; i < leaves.size(); i++) {
            dp[i][0] = dp[i - 1][0] + (leaves[i] == 'y');
            dp[i][1] = min(dp[i - 1][0],dp[i - 1][1]) + (leaves[i] == 'r');
            if (i >= 2) {
                dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]) + (leaves[i] == 'y');
            }
        }
        return dp[leaves.size() - 1][2];
    }
};

相關文章