记录今天学习的三道算法题:两道滑动窗口和一道栈的应用。
2904. 最短且字典序最小的美丽子字符串
题目描述

思路
滑动窗口
解题过程
题目要求找到包含
k个 ‘1’ 的子字符串,并且需要满足两个条件:
- 最短长度:在所有包含
k个 ‘1’ 的子字符串中,长度最小。- 字典序最小:如果存在多个长度最短的子字符串,选择字典序最小的那个。
我们可以使用滑动窗口来解决这个问题。维护一个窗口
[left, right],以及窗口内 ‘1’ 的计数count。
- 扩展窗口:移动
right指针向右扩展窗口。如果s[right]是 ‘1’,则count增加。- 检查与收缩窗口:当
count达到k时,当前窗口[left, right]就包含恰好k个 ‘1’ 了吗?不一定,可能count > k。 我们需要一个while循环,当count >= k时:
- 找到有效子串:如果
count == k,此时窗口[left, right]是一个包含k个 ‘1’ 的有效子字符串。我们计算其长度len = right - left + 1。- 更新结果:
- 如果
len小于当前记录的最短长度retLen,则更新retLen = len,并将当前子字符串s.substring(left, right + 1)存为retString。- 如果
len等于retLen,则比较当前子字符串s.substring(left, right + 1)与retString的字典序,如果当前子字符串字典序更小,则更新retString。- 收缩窗口:为了寻找可能更短的或者字典序更小的有效子串(或者单纯为了让窗口继续滑动),我们需要移动
left指针向右收缩窗口。如果滑出窗口的字符s[left]是 ‘1’,则count减少。然后left++。- 循环与结束:
right指针遍历完整个字符串后结束。- 返回结果:如果
retLen仍然是初始值n + 1,说明没有找到包含k个 ‘1’ 的子字符串,返回空字符串"";否则返回retString。
复杂度
- 时间复杂度: O ( n ) O(n) O(n) - 每个字符最多进出窗口一次。字符串比较在最坏情况下可能达到 O ( n ) O(n) O(n),但均摊下来,总复杂度仍接近 O ( n ) O(n) O(n)。
- 空间复杂度: O ( 1 ) O(1) O(1) - 只使用了常数级别的额外空间(不算存储结果字符串的空间)。
Code
class Solution {
public String shortestBeautifulSubstring(String s, int k) {
String retString = "";
int n = s.length();
int retLen = n + 1;
int count = 0;
for (int left = 0, right = 0; right < n; right++) {
char in = s.charAt(right);
// 进窗口
if (in == '1') {
count++;
}
// 判断与收缩
while (count >= k) {
if (count == k) {
int len = right - left + 1;
// 更新结果
String currentSub = s.substring(left, right + 1);
if (len < retLen) {
retLen = len;
retString = currentSub;
} else if (len == retLen) {
if (retString.isEmpty() || currentSub.compareTo(retString) < 0) {
retString = currentSub;
}
}
}
// 出窗口
if (s.charAt(left) == '1') {
count--;
}
left++;
}
}
return (retLen == n + 1) ? "" : retString;
}
}
209. 长度最小的子数组
题目描述

思路
滑动窗口
解题过程
维护一个滑动窗口
[left, right]和窗口内元素的和sum。
- 扩展窗口:
right指针向右移动,将nums[right]加入sum。- 检查与收缩窗口:使用
while循环检查sum是否大于等于target。
- 如果
sum >= target,说明当前窗口[left, right]是一个满足条件的子数组。记录其长度right - left + 1,并更新全局最小长度ret。- 收缩窗口:因为题目要求最小长度,并且数组元素都是正数,所以当前窗口已经满足条件后,可以尝试缩短它。将
nums[left]从sum中减去,并将left指针右移 (left++)。继续在while循环内检查sum是否仍然满足>= target。- 循环与结束:
right指针遍历完整个数组后结束。- 返回结果:如果
ret仍然是初始的最大值Integer.MAX_VALUE,说明没有找到满足条件的子数组,返回 0;否则返回ret。
复杂度
- 时间复杂度: O ( n ) O(n) O(n) - 每个元素最多进出窗口一次。
- 空间复杂度: O ( 1 ) O(1) O(1) - 只使用了常数级别的额外空间。
Code
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int ret = Integer.MAX_VALUE;
int sum = 0;
int n = nums.length;
for (int left = 0, right = 0; right < n; right++) {
// 进窗口
sum += nums[right];
// 判断与收缩
while (sum >= target) {
// 更新结果
ret = Math.min(ret, right - left + 1);
// 出窗口
sum -= nums[left];
left++;
}
}
// 返回结果
return ret == Integer.MAX_VALUE ? 0 : ret;
}
}
20. 有效的括号
题目描述

思路
栈 (Stack)
解题过程
利用栈的“后进先出”特性来匹配括号。
- 遍历字符串:逐个检查字符串中的字符。
- 左括号:如果遇到左括号(
(、[、{),将其压入栈中。- 右括号:如果遇到右括号(
)、]、}):
- 检查栈是否为空:如果此时栈为空,说明没有对应的左括号与之匹配,字符串无效,返回
false。- 检查栈顶元素:查看(不弹出)栈顶的左括号
look = stack.peek()。- 匹配判断:判断当前右括号
in是否与栈顶左括号look匹配。
- 如果匹配(例如
look == '('且in == ')'),则弹出栈顶元素stack.pop()。- 如果不匹配,说明括号类型不对应,字符串无效,返回
false。- 遍历结束:遍历完整个字符串后:
- 检查栈是否为空:如果栈为空,说明所有括号都成功匹配,字符串有效,返回
true。- 如果栈不为空,说明有多余的左括号没有被匹配,字符串无效,返回
false。优化: 可以在开始时检查字符串长度是否为奇数,如果是奇数,则肯定无效,可以直接返回
false。
复杂度
- 时间复杂度: O ( n ) O(n) O(n) - 只需遍历一次字符串。
- 空间复杂度: O ( n ) O(n) O(n) - 最坏情况下,如果字符串全是左括号,栈的大小会等于字符串长度。
Code
class Solution {
public boolean isValid(String ss) {
if (ss == null || ss.length() % 2 != 0) {
return false;
}
Stack<Character> stack = new Stack<>();
char[] s = ss.toCharArray();
for (int i = 0; i < s.length; i++) {
char in = s[i];
// 左括号入栈
if (in == '(' || in == '[' || in == '{') {
stack.push(in);
} else {
// 右括号处理
// 栈为空,但遇到右括号
if (stack.isEmpty()) {
return false;
}
char look = stack.peek();
// 检查是否匹配
if ((look == '(' && in == ')') ||
(look == '[' && in == ']') ||
(look == '{' && in == '}')) {
stack.pop();
} else {
// 没匹配上
return false;
}
}
}
// 遍历结束后,栈应该是空的
return stack.isEmpty();
}
}









![[创业之路-344]:战略的本质是选择、聚焦, 是成本/效率/低毛利优先,还是差易化/效益/高毛利优先?无论是成本优先,还是差易化战略,产品聚焦是前提。](https://i-blog.csdnimg.cn/direct/2f1e278ce98d4f0ab2329af51beb1994.png)









![[Java微服务架构]4_服务通信之客户端负载均衡](https://i-blog.csdnimg.cn/direct/2feeeb2030f44360a9df25de2035636d.png)