題目連結:
題目意譯:
給定兩字串 s 和 t 其長度依序為 m 和 n,回傳 s 的最小視窗子字串使得每個 t 中的字元(包含重複的字元)都包含於該視窗中。如果沒有這樣子的子字串,則回傳空字串 ""。
測資之生成保證答案唯一。
一個子字串為一個字串中的連續字元序列。
限制:
m == s.length
n == t.length
1 ≦ m 、 n ≦ 10 ^ 5
s 和 t 由大小寫英文字母組成。
進階: 你可以找到一個 O(m + n) 時間複雜度的演算法嗎?
範例測資:
範例 1:
輸入: s = "ADOBECODEBANC", t = "ABC"
輸出: "BANC"
解釋: 最小視窗子字串 "BANC" 包含字串 t 中的 'A' 、 'B' 和 'C'。
範例 2:
輸入: s = "a", t = "a"
輸出: "a"
解釋: 整個字串 s 即是最小視窗。
範例 3:
輸入: s = "a", t = "aa"
輸出: ""
解釋: t 的兩個 'a' 都必須包含於視窗中。
由於 s 的最大視窗只含有一個 'a',因此回傳空字串。
解題思維:
由於題目本身就有提到視窗了,所以我們可以從滑動視窗(Sliding Window,如
這題和
這題)發想:
利用一個陣列 C 來統計所有 t 中每個字元種類各出現幾次,例如 t = "AAB",則 C['A'] = 2 、 C['B'] = 1,其他字元則為 0。
接著利用兩個變數 L 、 R(初始都是 0)來代表我們的視窗 [L, R)(即 L 等於 R 時,代表視窗不存在),以及一變數 X(初始為 t.size())代表目前 t 中沒被配對到的字元數。
接著我們一直將視窗的右端點往右推進(R 之值遞增),對於每個 s 的字元 s[R]:
判斷 C[s[R]] 之值是否大於 0。如果是則代表 t 中還有 s[R] 這種的字元還沒被配對到,因此將 X 減去 1。
接著從 C[s[R]] 減去 1,代表把 s[R] 這個字元納入視窗之內。之後將 R 加上 1。
緊接著判斷 X 是否為 0。是 0 就重複以下步驟直到 X 不為 0:
因為 X 為 0,所以當前的視窗 [L, R) 包含著字串 t 所有字元。因此判斷 R - L(即視窗長度)是否比當前最小還要小,如果是就更新最小值以及這個最小發生所在位置,即 [L, R)。
接著把 s[L] 從視窗中移除。因為就算 R 在繼續增加也不會使長度更短,反而是捨棄掉 s[L] 才有可能遇到之後的最短子字串。
因此我們先判斷 C[s[L]] 是否大於等於 0,如果是則代表捨去 s[L] 後將會有 t 中的字元無法被配對到,因此 X 要加上 1。
因此我們將 C[s[L]] 加上 1。然後將 L 加上 1。
而上述過程中找到的最短長度之子字串即是所求;如果發現就算整個視窗擴大到 s 仍有 t 的字元無法配對,則回傳 ""。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。