刪除部分字符使其變成迴文串問題——最長公共子序列LCS問題

先要搞明白:最長公共子串和最長公共子序列的區別。java

最長公共子串(Longest Common Substirng):連續ui

最長公共子序列(Longest Common Subsequence,LCS):沒必要連續code

題目:給定一個字符串s,你能夠從中刪除一些字符,使得剩下的串是一個迴文串。如何刪除才能使得迴文串最長呢?
輸出須要刪除的字符個數。
字符串

思路是:反序這個字符串,求這個新串和原串的最大子序列。abcda--->adcba 最大子序列是aca,再相減就是最少的字符刪除個數。因此問題變成了求兩個字符串的最長子序列。get

那麼怎麼求兩個字符串的最長子序列呢?既然是用動態規劃,最重要的是肯定狀態和狀態轉移方程。io

狀態:當str1的下標爲m,str2的下標是n的時候(不考慮後面的),此時的最長子序列長度L。class

轉移方程:1,若是str1(m)==str2(n),那麼L(m,n)=L(m-1,n-1)+1。2,若是str1(m)!=str2(n),那麼L(m,n)=max(L(m-1,n),L(m,n-1))。next

解釋一下,假如m和n相等,那麼這個時候最長子序列無疑是前一個L(m-1,n-1)加上1,由於這兩個字符串這個地方的字符均可以加入到最長子序列裏面去。若是不相等,那麼要麼捨棄新來的來自str1的那個字符m號,要麼捨棄str2的n號字符(最長子序列每一個位置上固然都是惟一肯定的一個字符),捨棄以後呢,就從static

L(m-1,n),L(m,n-1)當中挑一個好的(能更長的)爲當前狀態的最長子序列。動態規劃

代碼:

public class Main {
     public static void main(String[] args){
         Solution s = new Solution();
         Scanner sc = new Scanner(System.in);
         while(sc.hasNextLine()) {
             System.out.println( s.getResult(sc.nextLine()) );
         }
         sc.close();
     }
}
 
class Solution {
     public int getResult(String s) {
         StringBuilder s1 = new StringBuilder(s);
         StringBuilder s2 = new StringBuilder(s).reverse();
         return s.length() - LCS(s1, s2);
     }
     public int LCS(StringBuilder s1, StringBuilder s2) {
         int m = s1.length();
         int n = s2.length();
         int[][] mutrix = new int[m + 1][n + 1];
         
         for(int i = 1; i <= m; i++) {
             for(int j = 1; j <= n; j++) {
                 if(s1.charAt(i - 1) == s2.charAt(j - 1))
                     mutrix[i][j] = mutrix[i - 1][j - 1] + 1;
                 else 
                     mutrix[i][j] = Math.max(mutrix[i - 1][j], mutrix[i][j - 1]);
             }
         }
         return mutrix[m][n];
     }
}
相關文章
相關標籤/搜索