演算法作業第十週(leetcode)——132.palindrome-partitioning-ii
阿新 • • 發佈:2018-12-20
其實已經不是特別想做動態規劃的題了,但是還是抽到了一道動態規劃的題。下面給出題目描述:
這題的大意是給一個字串,要經過最少多少次分割才能把字串分成迴文串組成的字串。
其實這題動態規劃的部分並不是特別難的部分。很容易就可以想到用cut[i]來表示前i個字元所能分成的迴文串的最小個數。然後用一個數組p[i][j]來表示[i,j)之間的子串是不是迴文串,然後就可實現cut[i]到cut[j]之間的狀態轉移。
我個人覺得難點主要在怎麼在o(n^2)時間內實現迴文串的判斷。如果直接遍歷,那肯定是o(n^3)。一開始想到棧,但是迴文串可能有奇數個字元,不能一一對應。後來看了一下網上發現,迴文串去掉兩邊相同的字元還是迴文串。利用這個性質,我們可以實現一個簡單的遞迴:
int p[2005][2005]; int cut[2005]; class Solution { public: int isParlindrome(string& s, int i,int j) { if(i>=j-1) return 1; if(p[i][j]!=-1) return p[i][j]; if(s[i]!=s[j-1]) return 0; p[i][j] = isParlindrome(s, i+1, j-1); return p[i][j]; } int minCut(string s) { int i,j; memset(p, -1, sizeof(p)); memset(cut, -1, sizeof(cut)); for(i=0;i<s.size();i++) { if(isParlindrome(s,0,i+1)) cut[i] = 1; for(j=0;j<i;j++) { if(isParlindrome(s,j+1,i+1)) { if(cut[i]!=-1) cut[i] = min(cut[i],cut[j]+1); else cut[i] = cut[j] + 1; } } } return cut[s.size()-1]-1; } };
這裡懶得寫vector,直接開了一波陣列然後memset。。。。。所以很慢。。。(個人感覺是這個原因,沒實驗過)
其實這個還可以用迴圈實現,不過我感覺要搞清陣列依賴的關係比較複雜,相對難想。我個人實現了一個迴圈版本:
int p[2005][2005]; int cut[2005]; class Solution { public: int minCut(string s) { int i,j; memset(p, -1, sizeof(p)); memset(cut, -1, sizeof(cut)); for(i=0;i<s.size();i++) { if(s[0]==s[i]&&(p[1][i]==1||i<=1)) { p[0][i+1] = 1; cut[i] = 1; } for(j=0;j<i;j++) { if(s[j+1]==s[i]&&(p[j+2][i]==1||j>=i-2)) { p[j+1][i+1] = 1; if(cut[i]!=-1) cut[i] = min(cut[i],cut[j]+1); else cut[i] = cut[j] + 1; } } } return cut[s.size()-1]-1; } };
快了一點,如果想要再快就改成vector寫法好了: