1. 程式人生 > >【leetcode】132.(Hard) Palindrome Patitioning II

【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;
	}
}

執行結果:
在這裡插入圖片描述