[LeetCode]132. Palindrome Partitioning II
题目描述
思路
动态规划
开始考虑,和单词划分很像
但是简单的遍历加计算是否回文串总共需要n^3的时间复杂度
优化:
先用动归判断字符串中的任一子串是否是回文串,这一过程可以在n^2时间复杂度完成,之后保存状态数组
之后动归来判断需要最少划分是多少,时间复杂度为n^2,在数组中查找是否回文串时间复杂度为常数
终极优化:
综合一起考虑
先初始化状态数组,每一位分别保存到当前位置的字符串需要切割的次数,初始化为当前字符串个数减一,之后进行遍历,对于第i位的字符,内层循环判断从i-j到i+j是否为回文串,如果是的话,那么dp[i + j + 1]位置的状态可以更新,注意在判断时需要考虑回文串是奇数个字符的回文串还是偶数个字符的回文串
代码
注释部分为自己写的优化部分
非注释部分是参考答案的最终优化
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
/*
public:
void getPalinSubstr(string s) {
isPalin.resize(s.size(), vector<int>(s.size()));
for (int i = s.size() - 1; i >= 0; --i) {
for (int j = i; j < s.size(); ++j) {
if (i == j)
isPalin[i][j] = 1;
else if (j == i + 1)
isPalin[i][j] = s[i] == s[j];
else
isPalin[i][j] = s[i] == s[j] && isPalin[i + 1][j - 1];
}
}
}
int minCut(string s) {
getPalinSubstr(s);
vector<int> res(s.size());
for (int i = 0; i < s.size(); ++i) {
if (isPalin[0][i] == 1) {
res[i] = 0;
}
else {
res[i] = res[i - 1] + 1;
for (int j = 0; j < i; ++j) {
if (isPalin[j + 1][i] == 1)
res[i] = min(res[i], res[j] + 1);
}
}
}
return res[s.size() - 1];
}
private:
vector<vector<int>> isPalin;
*/
public:
int minCut(string s) {
vector<int> dp(s.size() + 1);
for (int i = 0; i <= s.size(); ++i)
dp[i] = i - 1;
for (int i = 1; i <= s.size(); ++i) {
for (int j = 0; i - j >= 0 && i + j < s.size() && s[i - j] == s[i + j]; ++j)
dp[i + j + 1] = min(dp[i + j + 1], 1 + dp[i - j]);
for (int j = 0; i - j - 1 >= 0 && i + j < s.size() && s[i - j - 1] == s[i + j]; ++j)
dp[i + j + 1] = min(dp[i + j + 1], 1 + dp[i - j - 1]);
}
return dp[s.size()];
}
};
int main() {
Solution s;
cout << s.minCut("aab") << endl;
system("pause");
return 0;
}