您的位置:首页 > 其它

leetcode-Palindrome Partitioning II

2017-06-06 09:37 323 查看


Palindrome Partitioning II

Total Accepted: 11791 Total
Submissions: 66110

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.

Have you been asked this question in an interview?

Yes

这道题是Palindrome Partitioning的变形,要求求出最小的分割使得全部分割后的子串都是回文串。

能够在Palindrome Partitioning的基础上改动。在找到可行解时。更新最优解。

class Solution {
public:
int minCut(string s) {
ans = INT_MAX;
findMinCut(s, 0, 0);
return ans;
}
private:
int ans;

void findMinCut(const string &s, int k, int currCut) {
string substr;
for (int i=k; i<s.size(); ++i) {
if (isPalindrome(s, k, i)) {
if (i+1 == s.size()) {
if (currCut+1 < ans) {
ans = currCut+1;
}
} else {
findMinCut(s, i+1, currCut+1);
}
}
}
}

bool isPalindrome(const string &s, int b, int e) {
int i=b, j=e;
while (i<j) {
if (s[i] != s[j])
return false;
++i;
--j;
}
return true;
}
};


假设添加记忆化搜索+剪枝,还是会TLE。超时的case是一大串"aaaa...aa"的情况。

class Solution {
public:
int minCut(string s) {
minCutNum = INT_MAX;
vector<string> paths;
find(s, 0, paths);
return minCutNum;
}
private:
int minCutNum;
map<int, int> minCutsMap;
void find(const string& s, int ind, vector<string>& paths)
{
for (int i = ind; i < s.size(); ++i) {
if (isPalindrome(s, ind, i)) {
if (paths.size() > minCutNum)
continue;
if (minCutsMap.find(i+1) != minCutsMap.end()) {
if (paths.size() + minCutsMap.size() - 1 < minCutNum) {
minCutNum = paths.size() + minCutsMap.size() - 1;
}
continue;
}
paths.push_back(s.substr(ind, i - ind + 1));
if (i + 1 == s.size()) {
if (minCutNum > paths.size() - 1) {
minCutNum = paths.size() - 1;
}
paths.pop_back();
continue;
}
int num = paths.size();
minCutsMap[i + 1] = INT_MAX;
find(s, i + 1, paths);
if (minCutsMap[i + 1] > paths.size() - num) {
minCutsMap[i + 1] = paths.size() - num;
}
if (minCutNum == 0)
return;
paths.pop_back();
}
}
}
bool isPalindrome(const string& str, int begin, int end)
{
while (begin < end) {
if (str[begin] != str[end])
return false;
++begin; --end;
}
return true;
}
};


最后网上參考了别人的DP,自己写了下,最终看到Accepted。

初始化isPalindrome的方法也是用了DP的方法,跟计算矩阵连乘最小操作数类似。

如果字符串为str。长度为n,计算最小分割数的状态转移方程为:dp[i] = min{dp[j]+1,dp[i]}(j=i+1...n-1), 当中dp[i]为str[i]...str[n-1]的最小分割数。在做DP题时,要考虑清楚怎么存状态,以及状态是怎样转移的。DP的长处就是可以依据曾经的选择来做出当下最优的选择,像贪心算法就不能,仅仅有曾经局部最优的状态。

class Solution {
public:
int minCut(string s) {
int len = s.size();
bool **isPalindrome = new bool*[len];
for (int i = 0; i < len; ++i) {
isPalindrome[i] = new bool[len];
}
initIsPalindrome(isPalindrome, s);

int *dp = new int[len]; // dp[i] stores minimum cuts for s[i]...s[len-1]
for (int i = len - 1; i >= 0; --i) {
if (isPalindrome[i][len - 1]) {
dp[i] = 0;
continue;
}
dp[i] = INT_MAX;
for (int j = i + 1; j < len; ++j) {
if (isPalindrome[i][j - 1]) {
if (dp[j] + 1 < dp[i]) {
dp[i] = dp[j] + 1;
}
}
}
}
int ret = dp[0];
for (int i = 0; i < len; ++i)
delete []isPalindrome[i];
delete []isPalindrome;
delete dp;
return ret;
}
private:
void initIsPalindrome(bool ** isPalindrome, const string& s) {
int len = s.length();
for (int L = 1; L <= len; ++L) { // L is the length of substring, from 1 to len
for (int i = 0; i < len - L + 1; ++i) { // i is the starting index
int j = i + L - 1; // j is the ending index
if (L == 1) {
isPalindrome[i][j] = true;
} else if (L == 2) {
isPalindrome[i][j] = s[i] == s[j];
} else {
isPalindrome[i][j] = (s[i] == s[j]) && isPalindrome[i + 1][j - 1];
}
}
}
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: