題幹
palindrome-partitioning i
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
For example, given s =”aab”,
Return
[
["aa","b"],
["a","a","b"]
]
palindrome-partitioning ii
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s =”aab”,
Return1since the palindrome partitioning[“aa”,”b”]could be produced using 1 cut.
兩個迴文字符串的題,第一個要把字串都是迴文的情況都存儲下來,第二個是求得到字串都是迴文需要對原字符串分割多少次。
解題思路
第一個題
對字符串進行遍歷,每當找到一個迴文的子串之後,繼續找剩下的子串中的會問子串,利用遞歸直到找完整個字符串即可。動態規劃也可解。
第二個題
運用動態規劃的想法,主要步驟分爲3步。
1.子串substr(0,i+1)的最小回文分割爲dp[i],並且初始化,如果substr(0,i+1) 爲迴文子串,那麼dp[i]=0,即不需要分割,否則爲i,即分割i 次
任意大於1的i,子串substr(j,i+1),即遍歷i之前所有子串,是迴文子串,dp[i]=min(dp[i],dp[j-1]+1),即再分割一次。
如果子串substr(j,i+1)不是迴文,dp[i]=min(dp[i],dp[j-1]+i-j+1)
上述構成寫成代碼即可。
參考代碼
問題一:
class Solution {
public:
vector<vector<string>>res;//結果的每組子串存儲
vector<string> tmp;//當前子串
bool isPalindrome (string s)//是否爲迴文的判斷
{
if (s.size()<=0) return false;
int start=0,end=s.size()-1;
while(start<=end)
{
if(s[start]==s[end])
{
start++;
end--;
}
else return false;
}
return true;
}
void dfs(string s,int pos)//子串遍歷
{
if (pos>=s.size())//遞歸退出條件,原字符串全部遍歷之後退出遞歸
{
res.push_back(tmp);
return;
}
for(int i=0;i<=s.size()-pos;i++)
{
if (isPalindrome(s.substr(pos,i)))
{
tmp.push_back(s.substr(pos,i));//將回文子串存到結果中
dfs(s,pos+i);//從當前位置繼續後面的遍歷
tmp.pop_back();
}
}
}
vector<vector<string>> partition(string s)
{
dfs(s,0);
return res;
}
};
問題二:
class Solution {
public:
bool isPalindrome (string s)//迴文判斷
{
if (s.size()<=0) return false;
int start=0,end=s.size()-1;
while(start<=end)
{
if(s[start]==s[end])
{
start++;
end--;
}
else return false;
}
return true;
}
int minCut(string s)
{
int *dp=new int [s.length()];
int min;
for(int i=0;i<s.length();i++)
{
dp[i]=(isPalindrome(s.substr(0,i+1)))?0:i;//步驟1:初始化dp[i]
if (dp[i]==0)//當dp[i]爲0的時候必爲min,故直接下一次循環
continue;
for(int j=1;j<=i;j++)
{
if (isPalindrome(s.substr(j,i-j+1)))//步驟2
dp[i]=(dp[i]<dp[j-1]+1)?dp[i]:dp[j-1]+1;
else
dp[i]=(dp[i]<dp[j-1]+i-j+1)?dp[i]:dp[j-1]+i-j+1;//步驟3
}
}
return dp[s.length()-1];//返回dp最後的結果
}
};
方法討論
兩個題都可以用動態規劃解決,字符串子串的這種問題主要用類似於深度遍歷的方法,每次從當前位置向後遍歷,適合用遞歸。
易錯點
遞歸跳出條件
遞歸跳出是遍歷結束之後進行跳出。
邊界條件
1.迴文判斷的時候循環結束條件是要在前後兩個指針順序start<=end來結束,<或者=單獨條件都不可以。
2.第2題中的s.substr(j,i-j+1)迴文的判斷對於子串長度爲i-j+1。這個容易錯誤。