1. 程式人生 > >迴文字元分割

迴文字元分割

題目

最美字串 題目描述 字串有很多格式,我們定義最美字串為:能夠對稱的 比如“CBABC“, 因為字串本身和它的反轉字串是相同的,也即字串以中間字元為軸心呈對稱展開。 現在需要您幫忙提供方案能夠將任一字串經過最少切割次數使得每個子字串都是最美字串。

輸入說明 程式從當前路徑下的data.txt檔案中讀取測試資料。 檔案內容只有一行待測字串(只包含數字和字母,且區分大小寫, 字串長度不超過1KB)。

輸出說明 向標準輸出列印最少切割次數

示例1 輸入: ACDCDCDAD 最少需要切2次, 使得每個子串都變成最美字串, 比如: A|CDCDC|DAD, 所以輸出2

輸出: 2

示例2 輸入: ABA 不需要切割, 字串本身就是對稱的, 所以輸出0。

輸出: 0

思路

  1. 這是一道動態規劃問題,別用貪心~比如abacccaha,用貪心每次去分割最大的迴文字串顯然是錯誤的。
  2. 我們設定 dp[j] 表示從0到 j 的最小的分割數,每次遞增 j ,用 i 遍歷 j 到 0,尋找是否有迴文字串 SijS_{ij} ,如果有,其可能的最小值為 dp[i-1] + 1。我們遍歷所有可能,每次與 dp[j] 比較,則 dp[j] = min{dp[j], dp[i-1]+1},當然需要判斷一下邊界 i=0 的情況。
  3. 中間我們用二維陣列 p[i][j] 記錄 i 到 j 的子串是否為迴文字串。
  4. 時間複雜度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; }