子字串的定義和子串行的定義類似,但要求是連續分布在其他字串中。比如輸入兩個字串bdcaba和abcbdab的最長公共字串有bd和ab,它們的長度都是2。
最直接的解法自然是找出兩個字串的所有子字串進行比較看他們是否相同,然後取得相同最長的那個。對於乙個長度為n的字串,它有n(n+1)/2 個非空子串。所以假如兩個字串的長度同為n,通過比較各個子串其演算法複雜度大致為o(n4)。這還沒有考慮字串比較所需的時間。簡單想想其實並不需要取出所有的子串,而只要考慮每個子串的開始位置就可以,這樣可以把複雜度減到o(n3)。
但這個問題最好的解決辦法是動態規劃法,在後邊會更加詳細介紹這個問題使用動態規劃法的契機:有重疊的子問題。進而可以通過空間換時間,讓複雜度優化到o(n2),代價是空間複雜度從o(1)一下子提到了o(n2)。
從時間複雜度的角度講,對於最長公共子串問題,o(n2)已經是目前我所知最優的了,也是面試時所期望達到的。但是對於空間複雜度o(n2)並不算什麼,畢竟演算法上時間比空間更重要。
1.暴力求解
直觀的思路就是問題要求什麼就找出什麼。要子串,就找子串;要相同,就比較每個字元;要最長就記錄最長。
public
class
longestsubstring
public
static
intlongestcommonsubstring_n3(string str1, string str2)
if (longest < length)
}}
return longest;
}}
2. 動態規劃法
假設兩個字串分別為s和t,s[i]和t[j]分別表示其第i和第j個字元(字元順序從0開始),再令l[i, j]表示以s[i]和s[j]為結尾的相同子串的最大長度。應該不難遞推出l[i, j]和l[i+1,j+1]之間的關係,因為兩者其實只差s[i+1]和t[j+1]這一對字元。若s[i+1]和t[j+1]不同,那麼l[i+1, j+1]自然應該是0,因為任何以它們為結尾的子串都不可能完全相同;而如果s[i+1]和t[j+1]相同,那麼就只要在以s[i]和t[j]結尾的最長相同子串之後分別添上這兩個字元即可,這樣就可以讓長度增加一位。合併上述兩種情況,也就得到l[i+1,j+1]=(s[i]==t[j]?l[i,j]+1:0)這樣的關係。
最後就是要小心的就是臨界位置:如若兩個字串中任何乙個是空串,那麼最長公共子串的長度只能是0;當i為0時,l[0,j]應該是等於l[-1,j-1]再加上s[0]和t[j]提供的值,但l[-1,j-1]本是無效,但可以視s[-1]是空字元也就變成了前面一種臨界情況,這樣就可知l[-1,j-1]==0,所以l[0,j]=(s[0]==t[j]?1:0)。對於j為0也是一樣的,同樣可得l[i,0]=(s[i]==t[0]?1:0)。
public
class
longestsubstring
//方法二:動態規劃
public
static
intlongestcommonsubstring_n2_n2(string str1, string str2)
for (int i = 1; i < size1; ++i)
}}
for (int i = 0; i < size1; ++i)
}}
return longest;
}}
面試演算法 1 無重複字元的最長子串
示例 1 輸入 abcabcbb 輸出 3 解釋 因為無重複字元的最長子串是 abc 所以其長度為 3。示例 2 輸入 bbbbb 輸出 1 解釋 因為無重複字元的最長子串是 b 所以其長度為 1。示例 3 輸入 pwwkew 輸出 3 解釋 因為無重複字元的最長子串是 wke 所以其長度為 3。請...
Manacher演算法 最長子回文串
manacher演算法 這個演算法用來找出乙個字串中最長的回文子字串。如果採取暴力解最長回文子字串問題,大概可以有兩種思路 1.遍歷出所有子字串找其中最長的回文 2.從每個字元作為中心,向兩邊擴散看是否回文。第二種比第一種稍微高明一點,但是總體的複雜度還是o n 2 的。而manacher演算法可以...
Leetcode 最長子串
給定乙個字串,找出不含有重複字元的最長子串的長度。示例 給定 abcabcbb 沒有重複字元的最長子串是 abc 那麼長度就是3。給定 bbbbb 最長的子串就是 b 長度是1。給定 pwwkew 最長子串是 wke 長度是3。請注意答案必須是乙個子串,pwke 是 子串行 而不是子串。includ...