计算长度为k的连续子数组的最大总和
给定一个整数数组,计算长度为k的连续子数组的最大总和。
输入:arr [] = {100,200,300,400} k = 2
输出:700
解释:300 + 400 = 700
解决思路
- 暴力解法:从k到n-k+1,计算k长度大小的窗口。
- 计算
(0,k-1)
窗口的数据和,减去第一个,加上最后一个。求最大值。
Java实现
public class SlidingWindow {
public void maxSumSliding() {
//定义长度
int k = 2;
//定义数组
int[] arr = {100, 200, 300, 400};
int size = arr.length;
if (size < k) {
return;
}
int maxSum = 0;
for (int i = 0; i < k; i++) {
maxSum += arr[i];
}
for (int i = k; i < size; i++) {
maxSum = Math.max(maxSum + arr[i] - arr[i - k], maxSum);
}
System.out.println(maxSum);
}
}
3. 无重复字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
解决思路
- 发现前面子串中有该元素,需要移除旧的元素。不是第一个,不是全部移除,而是用while判断
set.contains(s.charAt(i))
。
Java实现
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
HashSet<Character> set = new HashSet<>();
int res = 0;
int start = 0;
for (int i = 0; i < len; i++) {
while (set.contains(s.charAt(i))) {
set.remove(s.charAt(start));
start++;
}
set.add(s.charAt(i));
res = Math.max(res, i - start + 1);
}
return res;
}
}
53. 最大子数组和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
解决思路
- 求子串的和,判断是否小于0,小于0,则不累加。
Java实现
class Solution_LC53_II {
public int maxSubArray(int[] nums) {
int res = Integer.MIN_VALUE;
int curSum = 0;
for (int i = 0; i < nums.length; i++) {
curSum += nums[i];
res = Math.max(curSum, res);
if (curSum < 0) {
curSum = 0;
}
}
return res;
}
}
76. 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
解决思路
- 计算字符串t中每个字符出现的次数
- 挨个添加字符串s中的字符,如果该字符数出现在s中的次数小于t,有效次数+1;
- 尝试删除最前面的元素,当满足t中不存在或者t中出现的次数小于s,最前面的字符是多余的。
- 当有效字符的长度等于t的长度,且截取的字符串长度小于最小值,更新。
Java实现
class Solution {
public String minWindow(String s, String t) {
HashMap<Character, Integer> st = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
Integer count = st.getOrDefault(t.charAt(i), 0);
st.put(t.charAt(i), count + 1);
}
String ans = "";
int len = Integer.MAX_VALUE;
int j = 0;
int count = 0;//有效字符
HashMap<Character, Integer> sh = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
sh.put(s.charAt(i), sh.getOrDefault(s.charAt(i), 0) + 1);
if (st.containsKey(s.charAt(i)) && sh.get(s.charAt(i)) <= st.get(s.charAt(i))) {
count++;
}
while (j < i && (!st.containsKey(s.charAt(j)) || sh.get(s.charAt(j)) > st.get(s.charAt(j)))) {
Integer cnt = sh.get(s.charAt(j));
sh.put(s.charAt(j), cnt - 1);
j++;
}
if (i - j + 1 < len && count == t.length()) {
len = i - j + 1;
ans = s.substring(j, i + 1);
}
}
return ans;
}
}
239. 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
解决思路
- 优先队列,倒序。最大的在最上面。判断最大的元素的索引是否超过窗口,
[i-k+1,i]
- 滑动窗口,判断队列首是否超过窗口,挨个将次大的元素排列在队列后面。
Java实现
优先队列
class Solution_LC239_II {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return new int[0];
}
int n = nums.length;
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((a, b) -> {
return b[1] > a[1] ? 1 : -1;
});
int[] res = new int[n - k + 1];
for (int i = 0; i < nums.length; i++) {
priorityQueue.offer(new int[]{i, nums[i]});
if (i >= k - 1) {
while (priorityQueue.peek()[0] <= i - k) {
priorityQueue.poll();
}
res[i - k + 1] = priorityQueue.peek()[0];
}
}
return res;
}
}
滑动窗口
class Solution_LC239_II {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new LinkedList<>();
int len = nums.length;
int[] res = new int[len - k + 1];
for (int i = 0; i < len; i++) {
while (!deque.isEmpty() && deque.peek() <= i - k) {
deque.poll();
}
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
deque.offer(i);
if (i - k + 1 >= 0) {
res[i - k + 1] = nums[deque.peek()];
}
}
return res;
}
}