LeetCode(97) 交錯字串

2022-05-07 08:15:09 字數 3426 閱讀 8999

hard!

題目描述:

給定三個字串 s1, s2, s3, 驗證 s3 是否是由 s1 和 s2 交錯組成的。

示例 1:

輸入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"

輸出: true

示例 2:

輸入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"

輸出: false

解題思路:

這道求交織相錯的字串和之前那道word break 拆分詞句 的題很類似,就像之前說的只要是遇到字串的子串行或是匹配問題直接就上動態規劃dynamic programming,其他的都不要考慮,什麼遞迴呀的都是浮雲,千辛萬苦的寫了遞迴結果拿到oj上妥妥time limit exceeded,所以還是直接就考慮dp解法省事些。一般來說字串匹配問題都是更新乙個二維dp陣列,核心就在於找出遞推公式。那麼我們還是從題目中給的例子出發吧,手動寫出二維陣列dp如下:

ø d b b c a

ø t f f f f f

a t f f f f f

a t t t t t f

b f t t f t f

c f f t t t t

c f f f t f t

首先,這道題的大前提是字串s1和s2的長度和必須等於s3的長度,如果不等於,肯定返回false。那麼當s1和s2是空串的時候,s3必然是空串,則返回true。所以直接給dp[0][0]賦值true,然後若s1和s2其中的乙個為空串的話,那麼另乙個肯定和s3的長度相等,則按位比較,若相同且上乙個位置為true,賦true,其餘情況都賦false,這樣的二維陣列dp的邊緣就初始化好了。下面只需要找出遞推公式來更新整個陣列即可,我們發現,在任意非邊緣位置dp[i][j]時,它的左邊或上邊有可能為true或是false,兩邊都可以更新過來,只要有一條路通著,那麼這個點就可以為true。那麼我們得分別來看,如果左邊的為true,那麼我們去除當前對應的s2中的字串s2[j - 1] 和 s3中對應的位置的字元相比(計算對應位置時還要考慮已匹配的s1中的字元),為s3[j - 1 + i], 如果相等,則賦true,反之賦false。 而上邊為true的情況也類似,所以可以求出遞推公式為:

dp[i][j] = (dp[i - 1][j] && s1[i - 1] == s3[i - 1 + j]) || (dp[i][j - 1] && s2[j - 1] == s3[j - 1 + i]);

其中dp[i][j] 表示的是 s2 的前 i 個字元和 s1 的前 j 個字元是否匹配 s3 的前 i+j 個字元,根據以上分析,可寫出**如下:

c++解法一:

class solution 

for (int i = 1; i <= n2; ++i)

for (int i = 1; i <= n1; ++i)

}return dp[n1][n2];}};

我們也可以把for迴圈合併到一起,用if條件來處理邊界情況,整體思路和上面的解法沒有太大的區別。

c++解法二:

1

class

solution else

if (i == 0

) else

if (j == 0

) else18}

19}20return

dp[n1][n2];21}

22 };

這道題也可以使用帶優化的dfs來做,我們使用乙個雜湊集合,用來儲存匹配失敗的情況,我們分別用變數i,j,和k來記錄字串s1,s2,和s3匹配到的位置,初始化的時候都傳入0。在遞迴函式中,首先根據i和j,算出key值,由於我們的雜湊集合中只能放乙個數字,而我們要encode兩個數字i和j,所以通過用i乘以s3的長度再加上j來得到key,此時我們看,如果key已經在集合中,直接返回false,因為集合中存的是無法匹配的情況。然後先來處理corner case的情況,如果i等於s1的長度了,說明s1的字元都匹配完了,此時s2剩下的字元和s3剩下的字元可以直接進行匹配了,所以我們直接返回兩者是否能匹配的bool值。同理,如果j等於s2的長度了,說明s2的字元都匹配完了,此時s1剩下的字元和s3剩下的字元可以直接進行匹配了,所以我們直接返回兩者是否能匹配的bool值。如果s1和s2都有剩餘字元,那麼當s1的當前字元等於s3的當前字元,那麼呼叫遞迴函式,注意i和k都加上1,如果遞迴函式返回true,則當前函式也返回true;還有一種情況是,當s2的當前字元等於s3的當前字元,那麼呼叫遞迴函式,注意j和k都加上1,如果遞迴函式返回true,那麼當前函式也返回true。如果匹配失敗了,則將key加入集合中,並返回false即可。

c++解法三:

1

class

solution

8bool helper(string& s1, int i, string& s2, int j, string& s3, int k, unordered_set&s)

18 };

既然dfs可以,那麼bfs也就坐不住了,也要出來浪一波。這裡我們需要用佇列queue來輔助運算,如果將解法一講解中的那個二維dp陣列列出來的tf圖當作乙個迷宮的話,那麼bfs的目的就是要從(0, 0)位置找一條都是t的路徑通到(n1, n2)位置,這裡我們還要使用雜湊集合,不過此時儲存到是已經遍歷過的位置,佇列中還是存key值,key值的encode方法跟上面dfs解法的相同,初識時放個0進去。然後我們進行while迴圈,迴圈條件除了q不為空,還有乙個是k小於n3,因為匹配完s3中所有的字元就結束了。然後由於是一層層的遍歷,所以要直接迴圈queue中元素個數的次數,在for迴圈中,對隊首元素進行解碼,得到i和j值,如果i小於n1,說明s1還有剩餘字元,如果s1當前字元等於s3當前字元,那麼把s1的下乙個位置i+1跟j一起加碼算出key值,如果該key值不在於集合中,則加入集合,同時加入佇列queue中;同理,如果j小於n2,說明s2還有剩餘字元,如果s2當前字元等於s3當前字元,那麼把s2的下乙個位置j+1跟i一起加碼算出key值,如果該key值不在於集合中,則加入集合,同時加入佇列queue中。for迴圈結束後,k自增1。最後如果匹配成功的話,那麼queue中應該只有乙個(n1, n2)的key值,且k此時等於n3,所以當queue為空或者k不等於n3的時候都要返回false。

c++解法四:

1

class

solution };

8while (!q.empty() && k

19if (j < n2 && s2[j] ==s3[k]) 25}

26}27 ++k;28}

29return !q.empty() && k ==n3;30}

31 };

LC97 交錯字串

給定三個字串 s1,s2,s3,驗證 s3 是否是由 s1 和 s2 交錯組成的。示例 1 輸入 s1 aabcc s2 dbbca s3 aadbbcbcac 輸出 true 示例 2 輸入 s1 aabcc s2 dbbca s3 aadbbbaccc 輸出 false 這個題可以用動態規劃解決...

ALGO Leetcode 97 交錯字串

原題鏈結 給定三個字串 s1 s2 s3,請你幫忙驗證 s3 是否是由 s1 和 s2 交錯 組成的。兩個字串 s 和 t 交錯 的定義與過程如下,其中每個字串都會被分割成若干 非空 子字串 s s1 s2 sn t t1 t2 tm n m 1 交錯 是 s1 t1 s2 t2 s3 t3 或者 ...

計蒜客 交錯字串

題目描述 aabd abdc aabdabdc aabc abad aabcbaad 方法分析 動態規劃。思路 構造乙個大小為 s1len 1 s2len 1 的矩陣 dp i j 的含義 s1的前i個字元能否和s2的前j個字元構成s3的前i j個字元 1.初始化dp 0 0 1 表示s3為空時,s...