最小窗口子序列
难度:
标签:
题目描述
代码结果
运行时间: 92 ms, 内存: 16.0 MB
/*
* 最小窗口子序列
*
* 思路:
* 1. 使用流来遍历字符串 S 和 T。
* 2. 当找到匹配的子序列时,记录其长度,并尝试找到更小的匹配子序列。
* 3. 最终返回最小长度的子序列。
*/
import java.util.Optional;
import java.util.stream.IntStream;
public class Solution {
public String minWindow(String S, String T) {
int sLen = S.length(), tLen = T.length();
int[] minLength = {Integer.MAX_VALUE};
String[] result = {""};
IntStream.range(0, sLen).filter(i -> S.charAt(i) == T.charAt(0)).forEach(i -> {
int sIndex = i, tIndex = 0;
while (sIndex < sLen && tIndex < tLen) {
if (S.charAt(sIndex) == T.charAt(tIndex)) {
tIndex++;
}
sIndex++;
}
if (tIndex == tLen) { // 完全匹配
int end = sIndex;
sIndex--; tIndex--;
while (tIndex >= 0) { // 反向收缩匹配子序列
if (S.charAt(sIndex) == T.charAt(tIndex)) {
tIndex--;
}
sIndex--;
}
sIndex++;
if (end - sIndex < minLength[0]) { // 更新最小长度和结果
minLength[0] = end - sIndex;
result[0] = S.substring(sIndex, end);
}
}
});
return result[0];
}
}
解释
方法:
题解采用的是双指针方法,首先使用两个指针 index_s1 和 index_s2 分别遍历 s1 和 s2。index_s1 用于在 s1 中寻找包含 s2 的子序列,而 index_s2 用于确保子序列中的字符顺序与 s2 相同。当 index_s2 等于 s2 的长度时,意味着找到了一个包含 s2 的子序列。接下来,通过向左移动 start 指针来缩短找到的子序列,直到它不再包含 s2 的所有字符。这样可以确保找到的子序列是最短的。最后,更新最小子序列和其长度,然后重置 index_s2 为 0 并将 index_s1 设置为 start,以便寻找下一个可能的子序列。
时间复杂度:
O(m * n)
空间复杂度:
O(1)
代码细节讲解
🦆
在算法中,如何确保`index_s2`在减少的过程中不会错过s2中的任何字符,特别是当s2中有重复字符时?
▷🦆
为什么在找到满足条件的子序列后需要从后向前搜索以缩短子序列长度?这样做的具体目的是什么?
▷🦆
当`index_s1`重新设置为`start`后,为什么不会错过其他可能的最小窗口子序列?
▷🦆
算法描述中提到,当找到一个满足条件的子序列后,会重新设置`index_s2`为0并将`index_s1`设置为`start`。这种方式是否可能导致算法效率低下,因为它可能会重复检查之前已经检查过的字符?
▷相关问题
最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 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 的子串中, 因此没有符合条件的子字符串,返回空字符串。
提示:
m == s.length
n == t.length
1 <= m, n <= 105
s
和t
由英文字母组成
进阶:你能设计一个在
o(m+n)
时间内解决此问题的算法吗?最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
示例 1:
输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
示例 2:
输入:nums = [2,2,2,2,2] 输出:1 解释:最长连续递增序列是 [2], 长度为1。
提示:
1 <= nums.length <= 104
-109 <= nums[i] <= 109