【秋葉收藏集】
傳送門
題意
給出一個字串,只包括兩個字元 'r' , 'y',現在可以把 'y' 變成 'r' ,把 'r' 變成 'y',問最少需要多少次,才能把這個字串變成 'r...y...r...'模式。
思路
一般這種題目我都是通過列舉端點解決。
字串下標從 1 開始,設兩個分段點分別為 \(p_1\),\(p_2\)。
那麼 區間\([1,p_1]\) 應該全部變為 \('r'\),區間\([p_1+1,p_2]\) 應該變成 \('y'\),區間\([p_2+1,len]\)應該變成 \('r'\)。
我們先列舉 \(p_1\) 的位置,再列舉 \(p_2\) 的位置,得到 \(p_2\) 為任意值時使得區間 \([p_1+1,len]\)
比如 \(yyyrryy\)
當 \(p_1\) 為 1 時,\(p_2\) 分別為 2,3,4,5,6時,使得區間 \([p_1+1,len]\)合法的操作次數分別為:
3 2 3 4 3
這時我們來看當 \(p_1\) 的位置往後遞推一個時相應的合法操作次數:
2 3 4 3 向後推了一個y
3 4 3 向後推了一個y
3 2 向後推了一個r
1 向後退了一個r
我們可以發現當往後推的這一個字元為 \('y'\) 時,操作次數不會發生變化,但是如果向後推的是 \('r'\),那麼整體會 -1。即:對於每一個 \(p_2\) ,\(p_1+1\)
首先當 \(p_1 ==1\) 時,可以求出此時所有 \(p_2\) 的操作次數,因為這些操作次數只會同時改變。
所以我們可以在 \(p_1==1\) 的時候就求出所有 \(p_1\) 的最佳位置。
對於任意一個 \(p_1\) 其答案為:
[1,p1]的'y'個數 + p1=1時求出的該位置p2的最佳位置的操作次數 - [2,p1]'r'的數量
程式碼
class Solution { public: int minimumOperations(string leaves) { int N = 1e5 + 10; int inf = 0x3f3f3f3f; int prer[N], prey[N], minn[N],ans[N]; int len = leaves.size(); leaves = "1" + leaves; for (int i = 1; i <= len; i++) { prer[i] = prer[i - 1] + (leaves[i] == 'r'); prey[i] = prey[i - 1] + (leaves[i] == 'y'); } minn[len] = inf; for (int i = len - 1; i>1; i--) { ans[i] = prer[i] - prer[1] + prey[len] - prey[i];//求出當p1為1時,p2為i時,使得區間[p1+1,len]合法時的次數 minn[i] = min(ans[i], minn[i + 1]);//求出當p1為i時,使得區間[p1+1,len]合法的最少的操作次數(需減去[2,i]出現過的'r'的數量) } int rel = inf; for (int i = 1; i < len - 1; i++) {//列舉p1 int now = prey[i] + minn[i + 1] - (prer[i] - prer[1]); rel = min(rel, now); } return rel; } };