问题描述:
Given strings S
and T
, find the minimum (contiguous) substring W
of S
, so that T
is a subsequence of 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]
.
解题思路:
仔细读题,注意这里说的是:子序列!!!
子序列意味着每个字符之间的相对顺序不能够改变。
解法参考了zestypanda的解法。
是用动态规划来进行解答。
首先搞清楚dp[j][i]的含义: 对于目标字符串T下标为[0,j]的子串作为子序列出现在给定字符串S[0, i]中的起始位置。
初始化dp[0][i]:当S[i] == T[0]时,dp[0][i] = i, else dp[0][i] = -1;
从T的第二个字符开始遍历。
我们用k记录对于T[0, j-1]在当前S[i]之前出现的下标。
当dp[j-1][i] != -1的时候表示到当前i,出现了T[0,j-1]的子序列。将其存入k
若S[i] == T[j], 且 k != -1,表示对于T[0, j]作为子序列出现了。更新dp[j][i].
现在dp中存储的是起始位置。但是我们想要知道的是长度最小的子串。
所以我们遍历dp[n-1][i] (因为要包含T作为子串),找到起始坐标start,子串长度i-start+1最小。
最后需要判断子串是否存在:
若start = -1,则不存在。
此时的空间复杂度为O(mn),可以通过滚动数组的方式,将其优化至O(m)
代码:
class Solution { public: string minWindow(string S, string T) { int m = S.size(), n = T.size(); vector<vector<int>> dp(n, vector<int>(m, -1)); for(int i = 0; i < m; i++){ if(S[i] == T[0]) dp[0][i] = i; } for(int j = 1; j < n; j++){ int k = -1; for(int i = 0; i < m; i++){ if(k != -1 && S[i] == T[j]) dp[j][i] = k; if(dp[j-1][i] != -1) k = dp[j-1][i]; } } int start = -1, len = INT_MAX; for(int i = 0; i < m; i++){ if(dp[n-1][i] != -1 && i - dp[n-1][i]+1 < len){ start = dp[n-1][i]; len = i - dp[n-1][i]+1; } } return start == -1 ? "":S.substr(start, len); } };