字节--字母交换
字節–字母交換
文章目錄
- 字節--字母交換
- 一、題目描述
- 二、分析
- 三、代碼
一、題目描述
字符串S由小寫字母構成,長度為n。定義一種操作,每次都可以挑選字符串中任意的兩個相鄰字母進行交換。詢問在至多交換m次之后,字符串中最多有多少個連續的位置上的字母相同?
- 輸入描述:
- 輸出描述:
二、分析
- 這題算是這場筆試最難的題了,區間動態規劃。
- 要求移動后形成的最長連續子串,這個最長連續子串可能全是a或b……c。因此,這里需要枚舉移動后形成的最長連續子串里面所包含的字母;
- 確定了里面包含的字母,就可以專注于這個字母了,也就是說其余的字母都是沒有用的,把它們從序列中挖掉;
- 然后就值剩下目標字母了,目標字母離散地分布在序列中,因此,再離散化一下,搞完之后會生成一個行的序列,之后的動態規劃就在新的序列上進行。
- 下面的圖片表達了上述過程:
- 現在新的序列pos看起來是合在了一起,形成了最長連續子序列,但是,形成這些連續序列所需要的操作次數是多少呢?如果操作次數大于m,那么該序列就是不滿足要求的;
- 因此,這里面就可以得出區間動態規劃了,先從小到大枚舉段長,依次求得該段長的所有子序列的操作次數,并判斷是否小于等于m,如果滿足要求,就更新答案。
- 從小到大枚舉段長是為了利用子問題的結果;dp[i][j]表示把pos[i]和pos[j]之間的目標字母移動到一起,形成j - i + 1長度的連續子序列所需要的操作次數;
- 狀態轉移方程:dp[i][i + len - 1] = dp[i + 1][i + len - 2] + pos[i + len - 1] - pos[i] - len + 1;
- 依據是|x?a|+|x?b||x?a|+|x?b|在什么時候取得最小值。用最小的移動次數把兩個目標字母移動到一起的方法就是把兩個目標字母都往中間靠,狀態轉移方程就是根據這個來的
- 先把pos[i + 1] ~ pos[i + len - 2]之間的目標字母移動到一起,這個移動次數就是dp[i + 1][i + len - 2],然后把兩個端點pos[i]和pos[i + len -1]處的目標字母往中間靠,所需要的移動次數是pos[i + len - 1] - pos[i] - len + 1。
三、代碼
#include <bits/stdc++.h> using namespace std;int main() {string s;int m;while (cin >> s >> m) {int ans = 1;//枚舉每一個字符for (char c = 'a'; c <= 'z'; c++) {//構建pos數組vector<int> pos;for (int i = 0; i < (int)s.size(); i++)if (c == s[i])pos.push_back(i);//過濾掉只出現一次的字符if (pos.size() < 2)continue;//dp數組int ret = 1;vector<vector<int> > dp(pos.size(), vector<int>(pos.size(), 0));for (int len = 2; len <= (int)pos.size(); ++len) {for (int i = 0; i + len - 1 < (int)pos.size(); i++) {dp[i][i + len - 1] = dp[i + 1][i + len - 2] + pos[i + len - 1] - pos[i] - len + 1;if (dp[i][i + len - 1] <= m)ret = len;}}ans = max(ans, ret);}cout << ans << endl;}return 0; }總結
- 上一篇: 字节--手串
- 下一篇: 二叉树构建及双向链表