题目来源
题目描述
class Solution {
public:
int minCut(string s) {
}
};
题目解析
分析数据量
- 1 0 3 10^3 103,所以算法时间复杂度最高 O ( N 2 ) O(N^2) O(N2),可以用dp来做
分析题意
从左到右尝试模型
思路
class Solution {
bool ispalindrome(std::string str, int i, int j){
if(i == j){
return true;
}
while ( i < j){
if(str[i] != str[j]){
return false;
}
i++;
j--;
}
return true;
}
// 从str[begin....]开始至少能组成几个回文串
int process(std::string &str, int begin){
int N = str.size();
if(begin == N){
return 0;
}
if(begin == N - 1){
return 1;
}
int next = INT32_MAX;
for (int end = begin; end < str.size(); ++end) {
if(ispalindrome(str, begin, end)){
next = std::min(next, 1 + process(str, end + 1));
}
}
return next;
}
public:
int minCut(string s) {
if(s.size() < 2){
return 0;
}
return process(s, 0) - 1;
}
};
会超时(时间复杂度O(N^3))。
class Solution {
bool ispalindrome(std::string str, int i, int j){
if(i == j){
return true;
}
while ( i < j){
if(str[i] != str[j]){
return false;
}
i++;
j--;
}
return true;
}
public:
int minCut(string str) {
if(str.size() < 2){
return 0;
}
int N = str.size();
std::vector<int> dp(N + 1);
dp[N] = 0;
dp[N - 1] = 1;
for (int begin = N - 2; begin >= 0; --begin) {
int next = INT32_MAX;
for (int end = begin; end < N; ++end) {
if(ispalindrome(str, begin, end)){
next = std::min(next, 1 + dp[end + 1]);
}
}
dp[begin] = next;
}
return dp[0] - 1;
}
};
还是超时
预处理结构: 定义dp[i][j]表示从[i…j]是不是回文
(0)dp长度为N - 1,高度为N - 1
(1)当
i
<
j
i < j
i<j时,不能形成有效区间,因此无用
(2)初始化dp表
- 第一步:填对角线,dp[i][i] = true
- 第二步:填倒数第二条对角线(j = i + 1):当str[i] == str[i + 1]时,dp[i][j + 1] = true
(3)对于dp[i][j]普通情况怎么填写
- 如果str[i] != dp[j],填false
- 否则,dp[i][j] = dp[i + 1][j - 1]
class Solution {
std::vector<std::vector<bool>> checkPalindrome(string str){
int N = str.size();
std::vector<std::vector<bool>> dp(N, std::vector<bool>(N));
for (int i = 0; i <= N - 1; ++i) {
dp[i][i] = true;
}
for (int i = 0; i <= N - 2; ++i) {
dp[i][i + 1] = str[i] == str[i + 1];
}
for (int i = N - 2; i >= 0; --i) {
for (int j = i + 2; j <= N - 1; ++j) {
dp[i][j] = str[i] == str[j] && dp[i + 1][j - 1];
}
}
return dp;
}
public:
int minCut(string str) {
if(str.size() < 2){
return 0;
}
int N = str.size();
std::vector<int> dp(N + 1);
dp[N] = 0;
dp[N - 1] = 1;
auto check = checkPalindrome(str);
for (int begin = N - 2; begin >= 0; --begin) {
int next = INT32_MAX;
for (int end = begin; end < N; ++end) {
if(check[begin][end]){
next = std::min(next, 1 + dp[end + 1]);
}
}
dp[begin] = next;
}
return dp[0] - 1;
}
};
扩展
返回一种可能的切分
示例待添加
实现
class Solution {
std::vector<std::vector<bool>> checkPalindrome(string str){
int N = str.size();
std::vector<std::vector<bool>> dp(N, std::vector<bool>(N));
for (int i = 0; i <= N - 1; ++i) {
dp[i][i] = true;
}
for (int i = 0; i <= N - 2; ++i) {
dp[i][i + 1] = str[i] == str[i + 1];
}
for (int i = N - 2; i >= 0; --i) {
for (int j = i + 2; j <= N - 1; ++j) {
dp[i][j] = str[i] == str[j] && dp[i + 1][j - 1];
}
}
return dp;
}
public:
std::vector<std::string> minCut(string str) {
int N = str.size();
std::vector<int> dp(N + 1);
dp[N] = 0;
dp[N - 1] = 1;
auto check = checkPalindrome(str);
for (int begin = N - 2; begin >= 0; --begin) {
int next = INT32_MAX;
for (int end = begin; end < N; ++end) {
if(check[begin][end]){
next = std::min(next, 1 + dp[end + 1]);
}
}
dp[begin] = next;
}
std::vector<std::string> ans;
for (int i = 0, j = 1; j <= N; ++j) {
if(check[i][j - 1] && dp[i] == dp[j] + 1){
ans.emplace_back(str.substr(i, j - i));
i = j;
}
}
return ans;
}
};
返回所有可能的结果(待完成)