[LeetCode] 727. Minimum Window Subsequence 最小窗口子序列

Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequenceof W.

If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such minimum-length windows, return the one with the left-most starting index.

Example 1:

Input: 
S = "abcdebdde", T = "bde"
Output: "bcde"
Explanation: 
"bcde" is the answer because it occurs before "bdde" which has the same length.
"deb" is not a smaller window because the elements of T in the window must occur in order.

Note:

  • All the strings in the input will only contain lowercase letters.
  • The length of S will be in the range [1, 20000].
  • The length of T will be in the range [1, 100].

给定字符串S和T,在S中寻找最小连续子串W,使得T是W的子序列。如果没有找到返回"",如果找到多个最小长度的子串,返回左 index 最小的。

解法1:暴力搜索brute force,对于每一个s[i],从s[0]到s[i]扫描,看是否按顺序满足目标字符。 显然要超时,不是题目要求的。

解法2: 动态规划DP,  二维数组dp[i][j]表示T[0...i]在S中找到的起始下标index,使得S[index, j]满足目前T[0...i]。首先找到能满足满足T中第一个字符T[0]的S中的字符下标存入dp[0][j],也就是满足第一个字符要求一定是从这些找到的字符开始的。然后在开始找第二个字符T[1],扫到的字符dp[j]存有index,说明可以从这里记录的index开始,找到等于T[1]的S[j]就把之前那个index存进来,说明从这个index到j满足T[0..1],一直循环,直到T中的i个字符找完。如果此时dp[i][j]中有index,说明S[index, j]满足条件,如有多个输出最先找到的。

State: dp[i][j],表示在S中找到的起始下标 index ,使得 S[index...j] 满足目前 T[0...i] 是其子序列。

function: dp[i+1][k] = dp[i][j]  if S[k] = T[i+1] , 如果查看到第i+1行(也就是第 T[i+1]  的字符),如果满足S[k] = T[i+1],就把上一行找到的index赋给它。

Initialize: dp[0][j] = j if S[j] = T[0] , 二维数组的第一行,如果字符S[j] = T[0], 就把S[j]的index(就是j)付给它。其他元素均为 None 或者 -1。

Return:  dp[len(T) - 1][j], if  dp[len(T) - 1][j] != None, 返回最小的。如果没有返回 ""

由于我们只用到前一行的值,所以可以只用2行的二维数组,每一个循环更新其中的一行。可以用 j % 2 来往复使用。

 

Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public String minWindow(String S, String T) {
        int m = T.length(), n = S.length();
        int[][] dp = new int[m + 1][n + 1];
        for (int j = 0; j <= n; j++) {
            dp[0][j] = j + 1;
        }
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (T.charAt(i - 1) == S.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = dp[i][j - 1];
            }
        }
        }
 
        int start = 0, len = n + 1;
        for (int j = 1; j <= n; j++) {
            if (dp[m][j] != 0) {
                if (j - dp[m][j] + 1 < len) {
                    start = dp[m][j] - 1;
                    len = j - dp[m][j] + 1;
                }
            }
        }
        return len == n + 1 ? "" : S.substring(start, start + len);
    }
}

Java: brute force, Time O(s*t), Space O(s*t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution { 
    public String minWindow(String S, String T) { 
        int min = -1, idx = -1
        char[] Tc = T.toCharArray(); 
        char[] Sc = S.toCharArray(); 
        for(int i = 0;i < S.length();i++){ 
            if(Sc[i] != Tc[0]) continue
            int len = check(Tc,Sc,i); 
            if(len <= 0) break
            if(min == -1 || len < min){ 
                idx = i; 
                min = len; 
            
        
        if(min == -1) return ""
        return S.substring(idx, idx + min); 
    
       
    public int check(char[] Tc, char[] Sc, int start){ 
        int i = start, j = 0
        while(i < Sc.length && j < Tc.length){ 
            if(Sc[i] == Tc[j]) j++; 
            i++; 
        
        if(j == Tc.length) return i - start; 
         
        return -1
    
}

Java:  DP, Time O(s*t), Space O(s*2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution { 
    public String minWindow(String S, String T) { 
        int[][] dp = new int[2][S.length()]; 
   
        for (int i = 0; i < S.length(); ++i) 
            dp[0][i] = S.charAt(i) == T.charAt(0) ? i : -1
   
        for (int j = 1; j < T.length(); ++j) { 
            int last = -1
            Arrays.fill(dp[j & 1], -1); 
            for (int i = 0; i < S.length(); ++i) { 
                if (last >= 0 && S.charAt(i) == T.charAt(j)) 
                    dp[j & 1][i] = last; 
                if (dp[j & 1][i] >= 0
                    last = dp[j & 1][i]; 
            
        
   
        int start = 0, end = S.length(); 
        for (int e = 0; e < S.length(); ++e) { 
            int s = dp[T.length() & 1][e]; 
            if (s >= 0 && e - s < end - start) { 
                start = s; 
                end = e; 
            
        
        return end < S.length() ? S.substring(start, end+1) : ""
    

Java: Time O(s*t), Space O(s*t)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
    public String minWindow(String S, String T) {
        int[][] dp = new int[T.length()][S.length()];
        for(int i = 0; i < T.length(); i++) {
            for(int j = 0; j < S.length(); j++) {
                dp[i][j] = -1;
            }
        }
         
        for(int j = 0; j < S.length(); j++) {
            dp[0][j] = (S.charAt(j) == T.charAt(0)) ? j : -1;
        }
         
        for(int i = 1; i < T.length(); i++) {
            int last = -1;
            for(int j = 0; j < S.length(); j++) {
                if(last >= 0 && S.charAt(j) == T.charAt(i)) {
                    dp[i][j] = last;
                }
                if(dp[i - 1][j] >= 0) {
                    last = dp[i - 1][j];
                }
            }
        }
         
        int start = -1;
        int length = Integer.MAX_VALUE;
         
        for(int j = 0; j < S.length(); j++) {
            if(dp[T.length() - 1][j] >= 0 && (j - dp[T.length() - 1][j] + 1 < length)) {
                start = dp[T.length() - 1][j];
                length = j - dp[T.length() - 1][j] + 1;
            }
        }
         
        return (start == -1) ? "" : S.substring(start, start + length);
    }
}

Python: Time O(s*t), Space O(s*2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution(object):
    def minWindow(self, S, T):
        dp = [[None for _ in xrange(len(S))] for _ in xrange(2)]
        for j, c in enumerate(S):
            if c == T[0]:
                dp[0][j] = j
                 
        for i in xrange(1, len(T)):
            prev = None
            dp[i%2] = [None] * len(S)
            for j, c in enumerate(S):
                if prev is not None and c == T[i]:
                    dp[i%2][j] = prev
                if dp[(i-1)%2][j] is not None:
                    prev = dp[(i-1)%2][j]
 
        start, end = 0, len(S)
        for j, i in enumerate(dp[(len(T)-1)%2]):
            if i >= 0 and j-i < end-start:
                start, end = i, j
        return S[start:end+1] if end < len(S) else ""

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution(object):
    def minWindow(self, S, T):
        """
        :type S: str
        :type T: str
        :rtype: str
        """
        ans = ''
        ls, lt = len(S), len(T)
        dp = [-1] * lt
        for x in range(ls):
            for y in range(lt - 1, -1, -1):
                if T[y] == S[x]:
                    dp[y] = dp[y - 1] if y else x
                    if y == lt - 1 and dp[-1] > -1:
                        nlen = x - dp[-1] + 1
                        if not ans or nlen < len(ans):
                            ans = S[dp[-1] : x+1]
        return ans

C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
 * At time j, for each position e in S (e for end), let's remember
 * the largest index cur[e] = s (for start) so that S[s: e+1] has
 * T[:j+1] as a subsequence, and -1 otherwise if it isn't possible.
 */
class Solution {
public:
    string minWindow(string S, string T) {
        int sn = S.size(), tn = T.size();
        vector<int> memo(sn, -1);
     
        for (int i = 0; i < sn; ++i) {
            if (T[0] == S[i]) {
                memo[i] = i;
            }
        }
         
        for (int j = 1; j < tn; ++j) {
            vector<int> swap(sn, -1);
            int currStart = -1;
             
            for (int i = 0; i < sn; ++i) {
                if (S[i] == T[j] && currStart >= 0) { // T[:j+1] found
                    swap[i] = currStart;
                }
                 
                if (memo[i] >= 0) {
                    currStart = memo[i];
                }
            }
            std::swap(memo, swap);
        }
         
        int BAR = sn + 1, minLen = BAR;
        int start = 0;
         
        for (int e = 0; e < sn; ++e){
            if (memo[e] >= 0) {
                int currLen = e + 1 - memo[e];
                if (currLen < minLen) {
                    start = memo[e];
                    minLen = currLen;
                }
            }
        }
        return minLen == BAR ? "" : S.substr(start, minLen);
    }
};

C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
    string minWindow(string s, string t) {
        int ns = s.size(), nt= t.size();
        int dp[ns+1][nt+1] = {};
        const int mxx = ns + 1;
        //for(int i=0;i<=ns;i++) dp[i][0]=i;
         
        for (int i = 0 ; i <= ns; ++i) {
            for (int j = 1; j <= nt; ++j) {
                dp[i][j] = mxx;
                if (i) {
                    dp[i][j] = min(dp[i][j], 1 + dp[i-1][j]);
                    if (s[i-1] == t[j-1]) dp[i][j]  = min(dp[i][j], 1 + dp[i-1][j-1]);
                }
            }
        }
         
        int ans = ns + 1, x = -1;
        for (int i = 0; i <=ns; ++i)
            if (dp[i][nt] < ans) {
            x = i;
            ans = dp[i][nt];
        }
         
        if (x < 0) return "";
        return s.substr(x-ans,ans);
    }
};

  

   

类似题目:

[LeetCode] 3.Longest Substring Without Repeating Characters 最长无重复子串

[LeetCode] 76. Minimum Window Substring 最小窗口子串

 

All LeetCode Questions List 题目汇总

  

posted @   轻风舞动  阅读(2797)  评论(1编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示