516.最長の回文サブシーケンス(中)

アイデア:

2の長さから開始して、各長さを左から右にトラバースして、長さが満たされているかどうかを確認します(重複サブ問題

長さに1を加えて、それが満たされているかどうかを比較します。満たされていない場合は、前の長さの最適解を取ります(最適解問題)。

 

コード:

class Solution {
    public int longestPalindromeSubseq(String s) {
		int n=s.length();
		
		//这里的dp表示长度,不表示数值
		int[][] dp=new int[n][n];
		
		//将dp的对角线元素置为1,意思是单个元素时,长度为1
		//因为是二维数组,不能用Arrays.fill()直接填满为1
		for(int i=0;i<n;i++){
			dp[i][i]=1;
		}
		
		//从2开始,逐个增加长度,不是累加,而是每次都是重新选值
                //len的条件设置为<=n
		for(int len=2;len<=n;len++){
			//从头开始遍历
			for(int i=0;i<n-len+1;i++){
                                //设置j为对应i这个头元素的尾元素
				int j=i+len-1;
				//若头尾的字符相同,符合条件,长度直接+len
				if(s.charAt(i)==s.charAt(j)){
					//dp[i+1][j-1]表示中间的最优解
					dp[i][j]=2+(len==2?0:dp[i+1][j-1]);
				}else{
					dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
				}
			}
		}
                //此时0~n-1是最优解,而不是还有1的可能
		return dp[0][n-1];
    }
}

 

壊す:

1)ここで、dpは2番目の形式です。現在の値は以前に計算されたすべての値に依存します

区間計画:通常、dp [i] [j]を使用して、i番目の位置からj番目の位置までの最良の状態または結果を表します。

dpは、最初の数値から2番目の数値までの長さを表します。その後、添え字をnに設定でき、n + 1に設定する必要はなく、添え字のオーバーフローの問題は発生しません。

 

2)対角線を1に設定します。これは、単一の要素にそれ自体が含まれている場合、回文サブシーケンスの長さが1であることを意味します。

for(int i=1;i<n;i++){
    dp[i][i]=1;
}

 

3)ダブルトラバーサルのみを設定します(len、i)

頭iを最初から最後までトラバースするだけでよく、jは毎回iの変化に伴って移動するだけでよく、jをトラバースする必要はありません。

for(int len=2;len<=n;len++)
	for(int i=0;i<n-len+1;i++)          
	    int j=i+len-1;

 

4)コアコード:

len == 2の場合、頭と尾が条件を満たす場合、長さは2です。

len == 3の場合、頭と尾は条件を満たし、長さは2+中間最適解dp [i + 1] [j-1]です。

                      頭と尾が条件を満たさない場合、長さはiとjの間の最適解、dp [i + 1] [j]またはdp [i] [j-1]です。

if(s.charAt(i)==s.charAt(j)){
    //dp[i+1][j-1]表示中间的最优解
    dp[i][j]=2+(len==2?0:dp[i+1][j-1]);
}else{
    dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
}

おすすめ

転載: blog.csdn.net/di_ko/article/details/115232281