動態規划:給出兩個字符串s1和s2,返回其中最大的公共子串


求公共子字符串問題(連續的)

這個題目是當時遠景能源公司現場筆試的一道題目,當時根本就不知道動態規划是什么鬼,直接上來就暴力求解,面試官很諂媚的問我,你這能求出來嗎?當時很年輕的說,能啊!現在想,當時哪來的自信和逗比勇氣說這大話。。。在《進軍硅谷》這本書上看到原題,我是懵逼,怎么想出這種解答出來的,下面直接上思路和代碼。

思路:

定義二維數組dp[i][j]記錄最大公共子串的長度,

  • 若要返回字符串可以用s1.substring(i-dp[i][j]+1, i+1)
  • 當s[i]==s[j]時,dp[i][j]=dp[i-1][j-1]+1;
  • 當s[i]!=s[j]時,dp[i][j]=0;

有點類似於數學歸納法

方案:

  • 首先考慮空或者長度為0的情況,直接返回"";
  • 然后進入雙重循環:
  • 1.利用charAt(int index)方法來比較兩個字符串相等的時機
  • 2.考慮邊界情況,兩個字符串中有一個是起始為0就相等,則dp[i][j]=1
  • 3.除了邊界情況,其他最大字符串長度為dp[i][j]=dp[i-1][j-1]+1;
  • 4.不斷的替換掉最大的長度並返回公共子串
  • 最后循環結束后,返回最大的公共子串
 1     public static String maxCommonString(String s1, String s2) {
 2         String res = "";
 3         if (s1 == null || s1.length() == 0 || s2 == null || s2.length() == 0)
 4             return res;
 5         int max = 0, m = s1.length(), n = s2.length();
 6         int[][] dp = new int[m][n]; // 定義一個二維數組記錄最大公共子串的長度
 7         // 計算到s1的第i個字符和s2的第j個字符為止的最大公共子串長度
 8         for (int i = 0; i < m; i++) {
 9             for (int j = 0; j < n; j++) {
10                 // 如果s1字符串在i處和s2字符串在j處有字符相同,進入if代碼塊中
11                 if (s1.charAt(i) == s2.charAt(j)) {
12                     if (i == 0 || j == 0)
13                         dp[i][j] = 1;// 邊界的情況
14                     else
15                         dp[i][j] = dp[i - 1][j - 1] + 1;// 加上當前長度
16                     // 記錄最大長度和子串
17                     if (dp[i][j] > max) {
18                         max = dp[i][j];
19                         res = s1.substring(i - dp[i][j] + 1, i + 1);// substring()左閉右開
20                     }
21                 }
22             }
23         }
24         return res;
25     }

動態規划介紹

動態規划算法一般是基於一個遞推公式(如上面的當s[i]==s[j]時,dp[i][j]=dp[i-1][j-1]+1;)以及一個或多個初始狀態(當s[i]!=s[j]時,dp[i][j]=0;),當前子問題其實是由上一次子問題的解推算出來的。
【附帶福利:markdown每行縮進的方式】

半方的空白&ensp;或&#8194;
全方的空白&emsp;或&#8195;
不斷行的空白格&nbsp;或&#160;
(分號都是英文格式的)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM