題目
最美字符串
題目描述
字符串有很多格式,我們定義最美字符串爲:能夠對稱的
比如“CBABC“, 因爲字符串本身和它的反轉字符串是相同的,也即字符串以中間字符爲軸心呈對稱展開。
現在需要您幫忙提供方案能夠將任一字符串經過最少切割次數使得每個子字串都是最美字符串。
輸入說明
程序從當前路徑下的data.txt文件中讀取測試數據。
文件內容只有一行待測字符串(只包含數字和字母,且區分大小寫, 字符串長度不超過1KB)。
輸出說明
向標準輸出打印最少切割次數
示例1
輸入:
ACDCDCDAD
最少需要切2次, 使得每個子串都變成最美字符串, 比如: A|CDCDC|DAD, 所以輸出2
輸出:
2
示例2
輸入:
ABA
不需要切割, 字符串本身就是對稱的, 所以輸出0。
輸出:
0
思路
- 這是一道動態規劃問題,別用貪心~比如abacccaha,用貪心每次去分割最大的迴文字符串顯然是錯誤的。
- 我們設置 dp[j] 表示從0到 j 的最小的分割數,每次遞增 j ,用 i 遍歷 j 到 0,尋找是否有迴文字符串 ,如果有,其可能的最小值爲 dp[i-1] + 1。我們遍歷所有可能,每次與 dp[j] 比較,則 dp[j] = min{dp[j], dp[i-1]+1},當然需要判斷一下邊界 i=0 的情況。
- 中間我們用二維數組 p[i][j] 記錄 i 到 j 的子串是否爲迴文字符串。
- 時間複雜度O(n^2)
代碼
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
int getMin(string s) {
int len = s.length();
int *dp = new int[len];
vector<vector<int>> p(len, vector<int>(len));
for (int j = 0; j<len; j++) {
dp[j] = 999;
for (int i = j; i >= 0; i--) {
if (s[i] == s[j] && (j - i<2 || p[i + 1][j - 1])) {
p[i][j] = true;
int t = (i == 0) ? 0 : (dp[i - 1] + 1);
if (t < dp[j]) dp[j] = t;
}
}
}
return dp[len - 1];
}
int main() {
string s;
fstream file("data.txt");
file >> s;
cout << getMin(s) << endl;
system("pause");
return 0;
}