【leetcode】132.(Hard) Palindrome Patitioning II

解题思路:

这道题用到了DP,以"gacbbcak"为例进行说明。

首先创建boolean二维数组:

第i行第j列表示字符串第i位到第j位字符是否构成回文串;
例如这个二维数组第3行第5列表示字符串的从第3位到第5位子串,"bbc"是否构成回文串,结果是flase;
左下三角由于i大于j构不成子串所以是空的(比如从原字符串从左到右第5位到第3位是构不成的子串):
在这里插入图片描述
填表的顺序为:
在这里插入图片描述
填表的原则为:

char[i] == char[j]&&i == j时 构成回文串,为true

例如对于"gacbbcak",i=j=2时,char[i]=char[j]=‘c’,表示的是子字符串"c",是回文的

char[i] == char[j]&&j-i==1时 构成回文串,为true

例如对于"gacbbcak",i=3,j=4时,表示子串"bb",是回文的


char[i] == char[j]&&j-i == 2时 构成回文串,为true

例如对于"aba"字符串来说,当i=0,j=2时,是回文的

char[i] == char[j]&&dp[i+1][j-1]时 构成回文串,为true

例如假设有下面的字符串:
在这里插入图片描述
当i=2,j=8时,char[i]==char[j]
同时只要dp[i+1][j-1]即中间那个红框中的部分是回文的,那从第2位到第8位就是回文的。
这里dp[i+1][j-1]是个布尔数值,表示字符串中从i+1位到j-1位是否是回文的


综上,这个二维数组中的元素dp[i][i]为true的条件是:

if(s.charAt(i)==s.charAt(j)&&((j-i<=2)||dp[i+1][j-1]))	
	dp[i][j]=true;

上面这句代码就包含了上面所有的填表原则。


计算minCut值:

对字符串"gacbbcak"填表:

g a c b b c a k
g 1 0 0 0 0 0 0 0
a 1 0 0 0 0 0 0
c 1 0 0 1 0 0
b 1 1 0 0 0
b 1 0 0 0
c 1 0 0
a 1 0
k 1

然后创建一个数组cnt[],用于保存字符串从第i位到最后一位有多少个回文串,i取值0~字符串长度
例如cnt[7]表示从字符串第7位到最后一位,即子串"k"有1个回文串;
cnt[3]表示子串"bbcak"中有多少个子回文串,有4个(“bb”,“c”,“a”,“k”);
计算的原则为:

cnt[i]=Math.min(1+cnt[j+1],cnt[i]);

例如:
在这里插入图片描述
在计算cnt[2]时,圆圈1中的dp[2][5]为true,说明方框2中的子串"cbbc"是回文的,那我直接调用cnt[6]即方框4中的数字来看一下剩下的"ak"中有多少个回文串即可。
可以看到cnt[6]=2, 即"ak"中有两个回文串(“a"和"k”)
所以cnt[2]=1+cnt[6]=3,即子串"cbbcak"中有3个回文串(“cbbc”, “a"和"k”)


提交代码:

class Solution{
	public int minCut(String s) {
		boolean[][] dp=new boolean[s.length()][s.length()];
		
		for(int i=s.length()-1;i>=0;i--) 
			for(int j=i;j<s.length();j++) 
				if(s.charAt(i)==s.charAt(j)&&((j-i<=2)||dp[i+1][j-1]))	dp[i][j]=true;
			
		int[] cnt=new int[s.length()+1];
		for(int i=s.length()-1;i>=0;i--) {
			cnt[i]=Integer.MAX_VALUE;
			for(int j=i;j<s.length();j++) {
				if(dp[i][j])
					cnt[i]=Math.min(1+cnt[j+1],cnt[i]);
			}
		}
		
		return cnt[0]-1;
	}
}

运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/AXIMI/article/details/84986659