大致思路如下:
给定一个序列,定义两个指针left,right,根据题意定义区间[left,right]之前的衡量指标f,比如区间和,乘积以及其他等。开始时left=right=0,计算指标f,left先不变,right往右边移动,更新f的值,当f符合一定条件时,left往右边移动,此时相当于区间变小,更新f的值,如果f一直符合题意,则left一直往右移动,如果f不符合题意,则left不变,继续移动right位置。如此往复,相当于一个滑动窗口把整个序列遍历了一遍,在整个过程中,当找到区间[left,right]时,可以记录过程中,最终获取极值。
来几道练习题
/** * 给定一个含有n个正整数的数组和一个正整数 target 。 * * 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr] , * 并返回其长度。如果不存在符合条件的子数组,返回 0 。 * * */
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int right = 0;
int sum = 0;
int min = Integer.MAX_VALUE;
// 如果总和小于target 则直接返回0
int total = Arrays.stream(nums).sum();
if (total < target) return 0;
// 双指针 右指针不停向右探索 一直找到符合条件的位置
// 此时左指针尝试向右 搜索更大的位置
for (right=0; right<nums.length; right++) {
sum = sum + nums[right];
while (sum >= target) {
min = Math.min(min, right-left+1);
sum = sum - nums[left];
left++;
}
}
return min;
}
/** * 给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。 * */
public int numSubarrayProductLessThanK(int[] nums, int k) {
int left = 0;
int right = 0;
int acc = 1;
int cnt = 0;
for (right=0; right<nums.length; right++) {
acc = acc * nums[right];
while (acc >= k && left <= right) {
acc = acc / nums[left];
left++;
}
if (left <= right) {
cnt = cnt + (right - left + 1);
}
}
return cnt;
}
/** * 给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。 * s 由英文字母、数字、符号和空格组成 * */
public int lengthOfLongestSubstring(String s) {
int max = 0;
Map<Character, Integer> map = new HashMap<>();
int left = 0;
int right = 0;
for ( ; right < s.length(); right++) {
map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) + 1);
while (!allLessThanOne(map) && left <= right) {
map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) - 1);
left++;
}
max = Math.max(max, right - left + 1);
}
return max;
}
private boolean allLessThanOne(Map<Character, Integer> map) {
return map.values().stream().filter(num -> num > 1).count() == 0;
}
/** * 给定两个字符串 s 和t 。返回 s 中包含t的所有字符的最短子字符串 * 如果 s 中不存在符合条件的子字符串,则返回空字符串 "" * 如果 s 中存在多个符合条件的子字符串,返回任意一个 * 注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量 * s 和 t 由英文字母组成 * */
public String minWindow(String s, String t) {
if (s.length() < t.length()) return "";
Map<Character, Integer> map = new HashMap<>();
for (char ch: t.toCharArray()) {
map.put(ch, map.getOrDefault(ch, 0) + 1);
}
int left = 0;
int right = 0;
int minLength = Integer.MAX_VALUE;
int minLeft = 0, minRight = 0;
for ( ; right < s.length(); right++) {
map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) - 1);
while (allLessEqualThanOne(map) && left <= right) {
if ((right-left) < minLength) {
minLeft = left;
minRight = right;
minLength = minRight - minLeft;
}
map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) + 1);
left++;
}
}
return minLength == Integer.MAX_VALUE ? "" : s.substring(minLeft, minRight + 1);
}
private boolean allLessEqualThanOne(Map<Character, Integer> map) {
return map.values().stream().filter(num -> num >= 1).count() == 0;
}