LCS 問題求解

LCS : longest common substring 即最長公共子串

LCS 問題就是求兩個字符串最長公共子串的問題洪唐。
解法就是用一個矩陣來記錄兩個字符串中所有位置的兩個字符之間的匹配情況涨冀,若是匹配則為1醉者,否則為0斟叼。然后求出對角線最長的1序列,其對應(yīng)的位置就是最長匹配子串的位置端逼。

但是在0和1的矩陣中找最長的1對角線序列又要花去一定的時間。通過改進(jìn)矩陣的生成方式和設(shè)置標(biāo)記變量洗贰,可以省去這部分時間。

當(dāng)字符匹配的時候陨倡,我們并不是簡單的給相應(yīng)元素賦上1敛滋,而是賦上其左上角元素的值加一。我們用兩個標(biāo)記變量來標(biāo)記矩陣中值最大的元素的位置兴革,在矩陣生成的過程中來判斷當(dāng)前生成的元素的值是不是最大的绎晃,據(jù)此來改變標(biāo)記變量的值,那么到矩陣完成的時候杂曲,最長匹配子串的位置和長度就已經(jīng)出來了庶艾。

算法的基本思想:
當(dāng)字符匹配的時候,不是簡單的給相應(yīng)元素賦上1擎勘,而是賦上其左上角元素的值加一咱揍。
我們用兩個標(biāo)記變量來標(biāo)記矩陣中值最大的元素的位置,在矩陣生成的過程中來判斷
當(dāng)前生成的元素的值是不是最大的棚饵,據(jù)此來改變標(biāo)記變量的值煤裙,那么到矩陣完成的時
候,最長匹配子串的位置和長度就已經(jīng)出來了蟹地。

C++ 實(shí)現(xiàn)

// std::format  為 C++20 特性
#include "stdc++.h"

using Table = std::vector<std::vector<int>>;

void print_table(const string& s1, const string& s2, const Table& t)
{
    cout << "  ";
    std::for_each(s1.cbegin(), s1.cend(), [](char ch){cout << format("{:>3}", ch);});
    cout << "\n";
    for (size_t i = 0; i < s2.size(); i++) {
        cout << format("{:>2}", s2[i]);
        for (size_t j = 0; j < s1.size(); j++)
            cout << format("{:>3}", t[i][j]);
        cout << "\n";
    }
}

string LCS(const string& s1, const string& s2)
{
    size_t s1_len = s1.size(), s2_len = s2.size();
    Table t(s2_len);
    std::for_each(t.begin(), t.end(), [s1_len](auto& v){ v.resize(s1_len); });

    size_t lcs_begin{}, lcs_end{}, lcs_len{};
    for (size_t i = 0; i < s2_len; i++) {
        for (size_t j =0; j < s1_len; j++) {
            if (s1[j] == s2[i]) t[i][j] = (i == 0 or j == 0) ? 1 :  t[i - 1][j - 1] + 1;  
            else t[i][j] = 0;
            if (lcs_len < t[i][j]) { lcs_len = t[i][j]; lcs_end = j; }
        }
    }
    print_table(s1, s2, t);
    lcs_begin = lcs_end - lcs_len + 1;

    return s1.substr(lcs_begin, lcs_len);
}

int main()
{
    string s1{"hello,world,123"};
    string s2{"HHHello,world,12345"};
    string lcs = LCS(s1, s2);
    cout << format("字符串: {} 和\n字符串: {} 的\n最長公共子串是:{}", s1, s2, lcs);
}

Python 實(shí)現(xiàn):

# LCS : longest common substring 即最長公共子串

def print_table(s1, s2, t):
    print("-"*20)
    print("  ", end='')
    for i in range(len(s1)):
        print("{:>3}".format(s1[i]), end = '')
    print("")

    for i in range(len(s2)):
        print("{:>2}".format(s2[i]), end = '')
        for j in range(len(s1)):
            print("{:>3}".format(t[i][j]), end = '')
        print("")
 
def LCS(s1, s2):
    print("尋找 {} 和 {} 的最大公共子串".format(s1, s2))
    s1_len, s2_len = len(s1), len(s2)
    t = [[0 for _ in range(s1_len)] for _ in range(s2_len)]
    lcs_begin, lcs_end, lcs_len = 0, 0, 0

    for i in range(s2_len):
        for j in range(s1_len):
            if s1[j] == s2[i]:
                if i == 0 or j == 0: t[i][j] = 1
                else:                t[i][j] = t[i - 1][j - 1] + 1
            else:                    t[i][j] = 0

            if t[i][j] > lcs_len:
                lcs_len = t[i][j]; lcs_end = j

    print_table(s1, s2, t)
    lcs_begin = lcs_end - lcs_len + 1

    return s1[lcs_begin : lcs_end + 1]

if __name__ == '__main__':
    strs = ["hello", "hell", "Hello", "llo", "hello, world"]
    print("字符串列表:", strs)
    lcs = strs[0]
    for s in strs[1:]:
        lcs = LCS(lcs, s)
    
    print("字符串列表的最長公共子串是:{}".format(lcs))                         
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末积暖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子怪与,更是在濱河造成了極大的恐慌夺刑,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件分别,死亡現(xiàn)場離奇詭異遍愿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)耘斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門沼填,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人括授,你說我怎么就攤上這事坞笙。” “怎么了荚虚?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵薛夜,是天一觀的道長。 經(jīng)常有香客問我版述,道長梯澜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任渴析,我火速辦了婚禮晚伙,結(jié)果婚禮上吮龄,老公的妹妹穿的比我還像新娘。我一直安慰自己咆疗,他們只是感情好漓帚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著民傻,像睡著了一般胰默。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漓踢,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天牵署,我揣著相機(jī)與錄音,去河邊找鬼喧半。 笑死奴迅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挺据。 我是一名探鬼主播取具,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扁耐!你這毒婦竟也來了暇检?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤婉称,失蹤者是張志新(化名)和其女友劉穎块仆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體王暗,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悔据,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了俗壹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片科汗。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绷雏,靈堂內(nèi)的尸體忽然破棺而出头滔,到底是詐尸還是另有隱情,我是刑警寧澤涎显,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布拙毫,位于F島的核電站,受9級特大地震影響棺禾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峭跳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一膘婶、第九天 我趴在偏房一處隱蔽的房頂上張望缺前。 院中可真熱鬧,春花似錦悬襟、人聲如沸衅码。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逝段。三九已至,卻和暖如春割捅,著一層夾襖步出監(jiān)牢的瞬間奶躯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工亿驾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嘹黔,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓莫瞬,卻偏偏與公主長得像儡蔓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疼邀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容