560. 和为 K 的子数组
题目链接
题目描述
代码实现
分析:
-
暴力:还是有点技巧的,如果单纯暴力,外层fori循环遍历起始下标start,内层forj循环遍历末尾end,里面还需要个循环,计算从i加到j,最坏会到\(O(n^3)\)。考虑固定某一个边界,比如固定end,从end往前算。
点击查看代码
class Solution {public int subarraySum(int[] nums, int k) {int count = 0;for (int i = 0; i < nums.length; i ++){int sum = 0;for (int j = i ; j >= 0; j--) {// 暴力 从后累加, 可以用到前一次的累加结果,有点像dp背包内循环遍历顺序的讨论sum += nums[j];if (sum == k){count++;}}}return count;} }
-
前缀和,类似1.两数之和
代码:
// 前缀和
class Solution {public int subarraySum(int[] nums, int k) {int count = 0;Map<Integer, Integer> map = new HashMap<>();int len = nums.length;int[] preSum = new int[len + 1];preSum[0] = 0;for (int i = 0; i < len; i++) {preSum[i + 1] = preSum[i] + nums[i];}for (int i = 0; i < nums.length; i++){// i 为0的时候, 就是计算 前缀子数组相加就是k的情况。// 前缀子数组的意思就是 从数组最开始到j的位置。[0,j]for(int j = i; j < nums.length; j++){// [i,j] 相加为kif(preSum[j+1] - preSum[i] == k){count++;}}}return count;}// 前缀和 + 哈希表
class Solution {public int subarraySum(int[] nums, int k) {int count = 0;Map<Integer, Integer> map = new HashMap<>();int sum = 0;map.put(0,1); // 初始化前缀和为0的次数为1, 也是一样的到里,当前缀子数组和为k的时候,需要计数1次for (int i = 0; i < nums.length; i++){// 这里的i相当于是 前缀和 解法中的j, 是右边界,sum - (sum - k) == k, 只需要在遍历到sum的时候// 看看此时的sum-k里的个数就行,也就是[left, i]中left的个数,在遍历的过程中,map里记录了left的个数sum += nums[i];if (map.containsKey(sum - k)) {count += map.get(sum - k);}map.put(sum, map.getOrDefault(sum, 0) + 1);}return count;}
}
239. 滑动窗口最大值
题目链接
题目描述
代码实现
分析:
- 使用一个单调队列完成,Deque来模拟单调队列。队列的顺序是从大到小。每次滑动窗口的过程可以分解为两个步骤:
- 左边界元素移出:移出时只需要判断一下是否是当前队列前端元素(最大值),如果是就移出队列。不是就说明移除的元素不是当前窗口的最大值,不做操作。
- 新增元素:新增元素时要判断加进来的元素与单调队列中的大小关系,按照约定的顺序,从队列尾部一个一个比较,队列尾部开始,比它小的元素都弹出,直到遇到大于等于这个新进来的元素时,加入队尾。
代码:
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {Deque<Integer> stack = new LinkedList<>();int n = nums.length;// 初始化单调栈 栈头->栈底: 大->小 小的并不是完全不要,而是舍去比新加进来的元素小的元素for(int i = 0; i < k; i++){while(!stack.isEmpty() && nums[i] > stack.peekLast()){stack.pollLast();}stack.offerLast(nums[i]);}int[] res = new int[n-k+1];res[0] = stack.peekFirst();// 模拟滑动窗口for(int i = k; i < n; i++){// 窗口左边界:当前需要移除窗口的元素if(nums[i-k] == stack.peekFirst()){stack.pollFirst();}// 窗口右边新加进来的元素需要和栈内元素进行比较 这里不能用>=,因为可能有重复元素while(!stack.isEmpty() && nums[i] > stack.peekLast()){stack.pollLast();}stack.offerLast(nums[i]);res[i-k+1] = stack.peekFirst();}return res;}
}
76. 最小覆盖子串
题目链接
题目描述
代码实现
分析:
代码: