每到周五就想放松么,还是写两个题解吧。今天写了几个问题,发现都是动态规划的问题。就说这两个吧。
题1:
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"] ]
找出所有的回文子串,如果是判断一个串是否是回文串,我想大家都应该能想出来。一般的判断一个串是否为回文串,直接从两头往中间找就可以了。这题的要求是让我们把这个字符串的所有子串都判断一遍。显然枚举每个子串的时间复杂度是O(n*n)的,加上判断的,算法时间复杂度是O(n*n*n)。同时判断完成时,还需要让原来的串划分为不同的回文串。这是个回溯,或者说dfs,因为要回复原来的状态,所要要回溯。
其实这是一个典型的动态规划问题,写这个的动态规划写法有几种。可以考虑从右往左,也可以从左往右。我在这里就写一个根据步长的。首先定义一个bool数组dp[i][j],表示从i到j是否是一个回文串。
状态转移,当dp[i+1][j-1]==1 &&s[i]==s[j] 或者只有一个元素 那么dp[i][j]=1;
步长++,就可以求出所有子串的状态。
有了第一步基础。下面的问题就变成了,搜索问题。很明显是一个深搜,出口条件是找到字符串最后位置。注意下回溯就好了。
class Solution {
public:
vector<vector<string>> ss;
bool dp[1500][1500];
vector<vector<string>> partition(string s) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int n=s.size();
if(s.size() == 0)
return vector<vector<string>>();
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
dp[i][j]=false;
dp[i][i]=true;
}
for(int k=1;k<n;k++)
{
for(int i=0;i<n-k;i++)
{
if(k==1 && s[i]==s[i+k])
dp[i][i+k]=true;
else
if(dp[i+1][i+k-1] &&s[i]==s[i+k])
dp[i][i+k]=true;
}
}
vector<string> tem;
dfs(0,n,s,tem);
return ss;
}
void dfs(int j,int n,const string &str,vector<string> &cur)
{
if(j==n)
{
ss.push_back(cur);
return ;
}
for(int k=j;k<n;k++)
{
if(dp[j][k])
{
string t(str.begin()+j,str.begin()+k+1);
cur.push_back(t);
dfs(k+1,n,str,cur);
cur.pop_back();
}
}
}
};
第二题,mark下 明天早上来写吧。。。。。教研室关门了。。。。。。。
教研室发了好多电影票,大家都去看电影啦,,我对电影没有兴趣,,还是继续写完吧。。。。。
题目2:
在要求几次分割可以将一个串分割为回文串。其实就是求一个串最少能用几个回文串表示嘛。所以我们求最少能用几个回文串表示就可以了。
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"
,
Return 1
since the palindrome partitioning ["aa","b"]
could be produced using 1 cut.
之所以超时,是因为没有办法有效利用前面信息,因为我是按步长求的,所以不能得到前面串的回文信息。所以这次我用从左往右的dp,可以利用前面求得的最少回文串。
思想就是从左往右开始,j=1;j++。。定义一个f[n]保存从0到i位置,最少回文串,初始时,f[i]=i+1;
求回文串的dp;
for(int j=1;j<n;j++)
{
for(int i=j;i>=0;i--)
{
if(s[i]==s[j] && (j-i<2||dp[i+1][j-1]))
dp[i][j]=true;
}
}
j
从左往右遍历,每次i--就可以求得0,j所有子串是否为回文串。。更新f状态也比较简单,当dp[i][j]==true的时候,我们需要更新我们的f,状态转移f[j]=min(f[i-1]+1,f[j]);
int minCut(string s) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int n=s.size();
vector<vector<bool> > dp(n,vector<bool>(n,false));
for(int i=0;i<n;i++)
dp[i][i]=true;
int f[n];
for(int i=0;i<n;i++)
f[i]=i+1;
for(int j=1;j<n;j++)
{
for(int i=j;i>=0;i--)
{
if(s[i]==s[j]&&(j-i<2||dp[i+1][j-1]))
{
dp[i][j]=true;
if(i==0)
f[j]=min(f[j],1);
else
f[j]=min(f[j],f[i-1]+1);
}
}
}
return f[n-1]-1;
}
写的匆忙,如果有不对的地方请大家多多指正。