560. 和为K的子数组
给你一个整数数组 nums
和一个整数 k
,请你统计并返回 该数组中和为 k
的连续子数组的个数 。
子数组是数组中元素的连续非空序列。
输入:nums = [1,1,1], k = 2 输出:2
思路: 前缀和+哈希表
思路分析:当定义前缀和 pre[ i ] 表示为[0,..,,i], 数组[j..i]的和可以表示为
经过移项可得:
因此,只需要判断中有多少值等于
即可得到答案。常见思路可以先得到前缀和数组
,再通过遍历得到符合条件的值。然而,这里有条件就
,因此,我们可以通过类似两数之和的做法,建立哈希表。以 前缀和 为键,前缀和出现的次数 为值。
通过每次查询哈希表中是否含有 ,如存在,则在,结果上加上相应的出现次数。
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
int count = 0;
int pre = 0;
int pre_k;
map.put(pre,1);
for (int i = 0; i < nums.length; i++) {
pre += nums[i];
pre_k = pre-k;
if(map.containsKey(pre_k)){
count += map.get(pre_k);
}
map.put(pre, map.getOrDefault(pre,0)+1);
}
return count;
}
}
239. 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7]
一般思路:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
LinkedList<Integer> quence = new LinkedList<>();
List<Integer> ans = new ArrayList<>();
// 初始队列
for (int i = 0; i < k; i++) {
quence.addLast(nums[i]);
}
ans.add(Collections.max(quence));
for (int i = k; i < nums.length ; i++) {
quence.addLast(nums[i]);
quence.removeFirst();
ans.add(Collections.max(quence));
}
return ans.stream().mapToInt(Integer::intValue).toArray();
}
}
使用队列进行出队,入队的遍历。但是超出了时间限制。因此,需要进一步优化。
思路:优先序列
使用优先序列分别保存{nums[i],i},数字和下标。为队列制定降序规则。
每次,向队列中存入一个数,使用下标接着判断这个数是否在滑动窗口内,如果不在滑动窗口内,
则移除最高值。
接着,将最大值导入ans中。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> -Integer.compare(o1[0],o2[0]));
for (int i = 0; i < k; i++) {
pq.offer(new int[] {nums[i],i});
}
int[] ans = new int[n-k+1];
ans[0] = pq.peek()[0]; // 获得优先级最高的元素;
for (int i = k; i < n; ++i) {
pq.offer(new int[] {nums[i],i});
while (pq.peek()[1] <= i - k) {
pq.poll();
}
ans[i - k + 1] = pq.peek()[0];
}
return ans;
}
}