求最短x模板
//求最短x模板:
初始化left,right,result,baseResult、
while(右指针没有到结尾){
窗口扩大,加入right对应元素,更新当前result
while(result满足要求){
更新最优结果bestResult
窗口缩小,移除left对应元素,left右移
}
right++;
}
返bestResult;
求最长x模板
初始化left,right,result,bestResultwhile
while(右指针没有到结尾) {
{
窗口扩大,加入right对应元素,更新当前resultwhilewhile(result不满足要求)
{
窗口缩小,移除left对应元素,left右移
}更新最优结果bestResult
right++;
}
返回bestResult;
这两个模板区块在求最短的是把 更新最优结果bestResult这部分放在第二个while循环里面,求最长的是放在第一个while循环里面。
例题:无重复字符的最长子串
给定一个字符串
s
,请你找出其中不含有重复字符的 最长子串 的长度。示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc"
,所以其长度为 3。示例 2:
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是"b"
,所以其长度为 1。示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串
这用滑动窗口最长x的模板来求
import java.util.*;
class Solution {
public int lengthOfLongestSubstring(String s) {
int left = 0; // 定义滑动窗口的左指针
int right = 0; // 定义滑动窗口的右指针
Map<Character, Integer> symbol = new HashMap(); // 使用HashMap存储字符及其出现的次数
char[] str = s.toCharArray(); // 将输入的字符串转换为字符数组
int result = 0; // 当前滑动窗口的长度
int baseResult = 0; // 最长不重复子串的长度
while (right < s.length()) { // 右指针未到达字符串末尾时循环
symbol.put(str[right], symbol.getOrDefault(str[right], 0) + 1); // 更新字符出现的次数
result++; // 滑动窗口长度加一
while (symbol.get(str[right]) > 1) { // 当出现重复字符时
symbol.put(str[left], symbol.get(str[left]) - 1); // 左指针指向的字符出现次数减一
result--; // 滑动窗口长度减一
left++; // 左指针向右移动
}
baseResult = Math.max(baseResult, result); // 更新最长不重复子串的长度
right++; // 右指针向右移动
}
return baseResult; // 返回最长不重复子串的长度
}
}
模板
public List<Integer> moudleFun(String s, String p) { List<Integer> result = new ArrayList<>(); Map<Character, Integer> need = new HashMap<>(p.length()); Map<Character, Integer> window = new HashMap<>(p.length()); for (int i = 0; i < p.length(); i++) { need.put(p.charAt(i), need.getOrDefault(p.charAt(i), 0) + 1); } int left = 0, right = 0; int valid = 0; while (right < s.length()) { char cur = s.charAt(right); right++; // 进行窗口内数据的一系列更新 ... // 判断左侧窗口是否要收缩 while (right - left >= p.length()) { // 当窗口符合条件时,把起始索引加入 result 中 if (valid == need.size()) { result.add(left); } char d = s.charAt(left); left++; // 进行窗口数据当一系列更新 ... } } return result; }
题目
给定两个字符串 s
和 t
。返回 s
中包含 t
的所有字符的最短子字符串。如果 s
中不存在符合条件的子字符串,则返回空字符串 ""
。
如果 s
中存在多个符合条件的子字符串,返回任意一个。
注意: 对于 t
中重复字符,我们寻找的子字符串中该字符数量必须不少于 t
中该字符数量。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最短子字符串 "BANC" 包含了字符串 t 的所有字符 'A'、'B'、'C'
class Solution {
public String minWindow(String s, String t) {
// 存储目标字符及其出现次数
Map<Character, Integer> need = new HashMap<>();
// 存储窗口内字符及其出现次数
Map<Character, Integer> window = new HashMap<>();
// 初始化need
for (char c : t.toCharArray()) {
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0;
int valid = 0;
int start = 0, len = Integer.MAX_VALUE;
while (right < s.length()) {
// c 是将移入窗口的字符
char c = s.charAt(right);
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
if (need.containsKey(c)) {
window.put(c, window.getOrDefault(c, 0) + 1);
if (window.get(c).equals(need.get(c))) {
valid++;
}
}
// 判断左侧窗口是否要收缩
while (valid == need.size()) {
// 在这里更新最小覆盖子串
if (right - left < len) {
start = left;
len = right - left;
}
// d 是将移出窗口的字符
char d = s.charAt(left);
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
if (need.containsKey(d)) {
if (window.get(d).equals(need.get(d))) {
valid--;
}
window.put(d, window.get(d) - 1);
}
}
}
// 返回最小覆盖子串
return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
}
}