Posted onEdited onInLeetCodeDisqus: Symbols count in article: 2.9kReading time ≈3 mins.
这道题跟76. Minimum Window Substring不一样,那个题是找anagram,不需要保持顺序,这个需要 O(mn) time O(mn) space 把S的每个字符的位置按顺序记录在对应的T的每个字符的bucket里,因为S里的子序列必须严格follow T的顺序所以T的每个bucket对应的下标必须严格递增,扫描所有的bucket将不合法的下标排除,每次扫完更新全局结果即可
classSolution { public: stringminWindow(string S, string T){ unordered_map<char, vector<int>> c2q; int m = S.length(), n = T.length(); for (int i = 0; i < n; ++i) { c2q[T[i]].push_back(i); } vector<queue<int>> q(n); for (int i = 0; i < m; ++i) { if (c2q.count(S[i])) { for (int j : c2q[S[i]]) { q[j].push(i); } } } if (q[0].empty()) return""; int l = -1, r = m; while (!q[0].empty()) { for (int i = 1; i < n; ++i) { while (!q[i].empty() && q[i - 1].front() >= q[i].front()) { q[i].pop(); } if (q[i].empty()) return l == -1 ? "" : S.substr(l, r + 1 - l); // 如果有任何一个bucket空了,说明S里不存在合法的子序列或者之前已找到的子序列已经最优 } if (q[n - 1].front() - q[0].front() < r - l) { l = q[0].front(); r = q[n - 1].front(); } q[0].pop(); } return S.substr(l, r + 1 - l); } };
双指针 O(mn) time O(1) space 先正着扫找符合要求的子序列,再倒着扫找到最短的子序列,类似sliding window
classSolution { public: stringminWindow(string S, string T){ int b = -1, len = INT_MAX; for (int m = size(S), n = size(T), i = 0, j = 0; i < m;) { while (i < m && j < n) { // 正向在S里找到第一个包含T序列的子串 if (S[i] == T[j]) ++j; ++i; } if (j == n) { // 如果找到 int e = i; // 先记录当前尾下标 --i; --j; // 回退两个指针 while (i >= 0 && j >= 0) { // 倒着在当前子串里找最大的起始下标 if (S[i] == T[j]) --j; --i; } ++i; ++j; // 修正指针得到最大起始下标 if (e - i < len) { // 更新结果 len = e - i; b = i; } ++i; // 别忘了找到了一个可能结果还要往前移动指针继续找 } } return b == -1 ? "" : S.substr(b, len); } };