1. 程式人生 > >華為OJ2011-最長公共子串

華為OJ2011-最長公共子串

一、題目描述

描述:

計算兩個字串的最大公共子串(Longest Common Substring)的長度,字元區分大小寫。

輸入:

輸入兩個字串

輸出:

輸出一個整數

樣例輸入:

asdfas werasdfaswer

樣例輸出:

6

二、解題報告

與最長公共子序列(參見《動態規劃DP》)一樣,最長公共子串也可以使用動態規劃解決,只不過思路不太一樣。準確地說,是打表的方式不一樣。

舉個例子:s1 = bab,s2 = caba。表如下



具體打表的方法是:

  • 第一行、第一列初始化為 0;
  • 對於其他的格子:
    • 若對應的兩個字元相等,格子的值設為左上角的值加 1。
    • 若對應的兩個字元不相等,直接置 0 。


這樣的話,表中的最大元素就是 最長公共子串 的長度。並且也可以很容易看出最長公共子串有 2 個,分別是baab

C++程式碼如下:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

int getLCStringLength(string s1, string s2)
{
    if(s1 == "" || s2 == "")
        return
0; int m = s1.size(); int n = s2.size(); vector<vector<int> > table(m+1, vector<int>(n+1)); int biggest = 0; // 記錄表中最大值 for(int i=0; i<m+1; ++i) { for(int j=0; j<n+1; ++j) { // 第一行和第一列置0 if (i == 0 || j == 0) table[i][j] = 0
; else if(s1[i-1] == s2[j-1]) { table[i][j] = table[i-1][j-1] + 1; if(table[i][j] > biggest) biggest = table[i][j]; } else // 不相等置0 table[i][j] = 0; } } return biggest; } int main () { string input, s1, s2; getline(cin, input); stringstream ss(input); ss >> s1; ss >> s2; cout << getLCStringLength(s1, s2) << endl; return 0; }

三、擴充套件

如何輸出所有的最長公共子串?

很簡單,我們記錄下 s1 和 s2 的公共子串分別在 s1 、s2 中起始位置(即表中值為 1 的座標)。打表完成以後,我們已經知道了最長公共子串的長度length,通過substr()判斷即可:

s1.substr(i-1, length) == s2.substr(j-1, length)

C++程式碼如下:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printLCString(string s1, string s2)
{
    if(s1 == "" || s2 == "")
        return;

    int m = s1.size();
    int n = s2.size();
    vector<vector<int> > table(m+1, vector<int>(n+1));

    int biggest = 0;  // 記錄表中最大值
    vector<pair<int, int> > firstPos;  // 記錄子串開始的座標 
    for(int i=0; i<m+1; ++i)  
    {  
        for(int j=0; j<n+1; ++j)  
        {  
            // 第一行和第一列置0  
            if (i == 0 || j == 0)  
                table[i][j] = 0;  
            else if(s1[i-1] == s2[j-1])  
            {
                table[i][j] = table[i-1][j-1] + 1;  
                if(table[i][j] > biggest)
                    biggest = table[i][j];
                if(table[i][j] == 1) 
                    firstPos.push_back(make_pair(i, j));
            }
            else  // 不相等置0
                table[i][j] = 0;  
        }  
    }

    // 輸出所有的最長公共子串
    vector<pair<int, int> >::iterator beg = firstPos.begin();
    for( ; beg!=firstPos.end(); ++beg)
    {
        int start1 = beg->first-1;
        int start2 = beg->second-1;
        if(s1.substr(start1, biggest) == s2.substr(start2, biggest))
            cout << s1.substr(start1, biggest) << endl;
    }
}


int main ()
{
    string s1 = "hello,world,james";
    string s2 = "james is saying hello";
    printLCString(s1, s2);

    return 0;
}