LeetCode 之 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",

Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

1.【基础知识】

1)substr函数掌握模糊;

2)动规与贪心算法的回顾;

3)树的深搜和广搜的应用能力;

4)fill_n函数。

2.【屌丝代码】

卡壳的地方:

1.剩下一个元素可以不切,直接判定跳出(已解决);

2.动规,一次循环同时进行前向与后向回文判定,并且采用初次前削判定和初次后削判定(已解决);

3.贪心,每次都比较,得到当下可以最快回文的长度,只不过未能实现(已解决);

4.解决了全部短小用例,倒在了代码中那段长不拉几的字符串用例上;

5.屌丝算法思想:

1)前向搜索:

1.1)先检查去掉最后Num个元素是不是回文;

1.1.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;

1.1.2)不是,继续循环体;

1.2)检查去掉最前Num个元素是不是回文;

1.2.1)是,则判断余下的是不是回文串——不是则直接进入下一层循环,是则直接跳出循环;

1.2.2)不是,继续循环体;

1.3)Num++

1.4)得到最终count_a;

2)后向搜索:

将1.1与1.2调换执行,得到最终count_b

3)比较count_a与count_b,返回最小值。

#include <vector>  
#include <iostream>
#include <algorithm> 
#include <vector>
#include <string>

using namespace std; 

class Solution {
public:
    int minCut(string s) 
	{
		int len = s.length();
		if(len<=1||IsPld(s)) 
			return 0;

		int tmp_len(len),cot_a(0),cot_b(0);
		string tmp_str = s;
		
		/*
		for(i=len-1;i>0;i--) // 切几刀? 如:0,表示不切,原字符串就是一个回文串
		{
			int *arr = (int*)malloc(sizeof(int)*(i+1));
			arr[0] = 0;
			vector<string> subs;
			for(j=1;j<=i+1;j++) // 循环刀数
				for(k>arr[j-1];k<) // 每一刀怎么切? 下刀点
				// 下一刀要比上一刀大;
				// 第一刀不能比0小;第一刀不能大于串长减刀数;
				// 第k刀不能比len-k大;
				// 最后一刀不能比串长大;
				{
					s.substr
				}
			delete []arr;
		}*/

		/*
		while(tmp_len)
		{
			if(IsPld(tmp_str.substr(0,tmp_len)))
			{
				cot_a++;
				tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
			}
			else 
				if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
				{
					cot_a++;
					tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
					tmp_len = tmp_str.size();
					if(IsPld(tmp_str))
						break;
				}
				else
				{
					tmp_len--;
				}
		}
		tmp_len = len;
		tmp_str = s;		
		while(tmp_len)
		{
			if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
			{
				cot_b++;
				tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
			}
			else 
				if(IsPld(tmp_str.substr(0,tmp_len)))
				{
					cot_b++;
					tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
					tmp_len = tmp_str.size();
					if(IsPld(tmp_str))
						break;
				}
				else
				{
					tmp_len--;
				}
		}
		return min(cot_a,cot_b);
		*/
		while(tmp_len)
		{
			if(IsPld(tmp_str.substr(0,tmp_len)))
			{
				cot_a++;
				tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
			}
			if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
			{
				cot_a++;
				tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
			}
				tmp_len--;
		}
		tmp_len = len;
		tmp_str = s;
		while(tmp_len)
		{
			if(IsPld(tmp_str.substr(tmp_str.size()-tmp_len,tmp_len)))
			{
				cot_b++;
				tmp_str = tmp_str.substr(0,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
				continue;
			}
			if(IsPld(tmp_str.substr(0,tmp_len)))
			{
				cot_b++;
				tmp_str = tmp_str.substr(tmp_len,tmp_str.size()-tmp_len);
				tmp_len = tmp_str.size();
				if(IsPld(tmp_str))
					break;
				continue;
			}
			tmp_len--;
		}
		return min(cot_b,cot_a);
    }
	bool IsPld(string s)
	{
		if(s.length()<=1)
			return true;
		int i(0),j(s.size()-1);
		while(i<j)
		{
			if(s[i]!=s[j])
				return false;
			i++;
			j--;
		}
		return true;
	}
};

int main()  
{
	string mystr = "adabdcaebdcebdcacaaaadbbcadabcbeabaadcbcaaddebdbddcbdacdbbaedbdaaecabdceddccbdeeddccdaabbabbdedaaabcdadbdabeacbeadbaddcbaacdbabcccbaceedbcccedbeecbccaecadccbdbdccbcbaacccbddcccbaedbacdbcaccdcaadcbaebebcceabbdcdeaabdbabadeaaaaedbdbcebcbddebccacacddebecabccbbdcbecbaeedcdacdcbdbebbacddddaabaedabbaaabaddcdaadcccdeebcabacdadbaacdccbeceddeebbbdbaaaaabaeecccaebdeabddacbedededebdebabdbcbdcbadbeeceecdcdbbdcbdbeeebcdcabdeeacabdeaedebbcaacdadaecbccbededceceabdcabdeabbcdecdedadcaebaababeedcaacdbdacbccdbcece";
	cout<<mystr.substr(1,2)<<endl; // string.substr(首元素索引,子串长度)
	Solution mySln;
	int num = mySln.minCut(mystr);
	cout<<num<<endl;
	while(1);
    return 0; 
}
3.【源码AC】

// LeetCode, Palindrome Partitioning II
// 时间复杂度 O(n^2),空间复杂度 O(n^2)
class Solution {
public:
    int minCut(string s) {
        const int n = s.size();
        int f[n+1];
        bool p[n][n];
        fill_n(&p[0][0], n * n, false);
        //the worst case is cutting by each char
        for (int i = 0; i <= n; i++)
        f[i] = n - 1 - i; // 最后一个 f[n]=-1
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if (s[i] == s[j] && (j - i < 2 || p[i + 1][j - 1])) {
                    p[i][j] = true;
                    f[i] = min(f[i], f[j + 1] + 1);
                }
            }
        }
    return f[0];
    }
};
4.【复盘】

1)卡壳部分
  • 不能解决的原因在于字符串太长,耗时也在1H以上,题目未解出来;
  • 动规的数学式子未能很好定义提炼。

2)AC源码思想——动态规划

定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
f(i, j) = min {f(i, k) + f(k + 1, j)} , i ≤ k ≤ j,0 ≤ i ≤ j < n
这是一个二维函数,实际写代码比较麻烦。所以要转换成一维 DP。如果每次,从 i 往右扫描,每找到一个回文就算一次 DP 的话,就可以转换为

 f(i) = 区间 [i, n-1] 之间最小的 cut 数

 n 为字符串长度,则状态转移方程为
f(i) = min {f(j + 1) + 1} , i ≤ j < n
一个问题出现了,就是如何判断 [i,j] 是否是回文?每次都从 i 到 j 比较一遍?太浪费了,这里也是一个 DP 问题。
定义状态  
P[i][j] = true if [i,j] 为回文  ,那么

P[i][j] = ( str[i] == str[j] && P[i+1][j-1] )


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值