6.12 二刷hot100 滑动窗口+子串
This commit is contained in:
parent
d3cfe89d74
commit
97564746ff
@ -28,6 +28,7 @@ import java.util.List;
|
||||
*/
|
||||
|
||||
//没做出来
|
||||
//二刷会做
|
||||
public class FindAnagrams {
|
||||
public List<Integer> findAnagrams(String s, String p) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
@ -1,6 +1,5 @@
|
||||
package slidingwindow;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
@ -23,7 +22,7 @@ import java.util.HashSet;
|
||||
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
|
||||
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
|
||||
*/
|
||||
|
||||
//二刷会做
|
||||
public class LengthOfLongestSubstring {
|
||||
public int lengthOfLongestSubstring(String s) {
|
||||
int left=0,right=0,max_length=0;
|
||||
|
@ -28,31 +28,55 @@ import java.util.*;
|
||||
输出:[1]
|
||||
*/
|
||||
//普通方法超时 需重做
|
||||
//二刷也没想到低复杂度方法
|
||||
public class MaxSlidingWindow {
|
||||
//优先队列
|
||||
/**
|
||||
* 思路说明:用优先队列(大顶堆)维护滑动窗口中的最大值
|
||||
* 滑动窗口长度为 k,我们每次都想拿到窗口内的最大值。
|
||||
* 用 PriorityQueue<int[]> 维护一个大顶堆:
|
||||
* 存入的是一个数组 new int[]{值, 下标};
|
||||
* 排序规则:按值降序,值相同时按下标降序(保证堆顶是最大值的最新位置)。
|
||||
* 每加入一个新元素,我们就把它压入堆;
|
||||
* 然后检查堆顶:如果它的下标已经滑出窗口左边(≤ i - k),就移除它;
|
||||
* 每次窗口滑完一个位置后,堆顶就是当前窗口最大值。
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int[] maxSlidingWindow1(int[] nums, int k) {
|
||||
int n = nums.length;
|
||||
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
|
||||
public int compare(int[] pair1, int[] pair2) {
|
||||
return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
|
||||
}
|
||||
});
|
||||
|
||||
// 优先队列(大顶堆),按值降序;如果值相同,则按下标降序(保证更靠右的元素在上面)
|
||||
PriorityQueue<int[]> pq = new PriorityQueue<>(
|
||||
(a, b) -> a[0] != b[0] ? b[0] - a[0] : b[1] - a[1]
|
||||
);
|
||||
|
||||
// 预处理第一个窗口:放入前 k 个元素
|
||||
for (int i = 0; i < k; ++i) {
|
||||
pq.offer(new int[]{nums[i], i});
|
||||
}
|
||||
|
||||
// 初始化结果数组(共 n - k + 1 个窗口)
|
||||
int[] ans = new int[n - k + 1];
|
||||
ans[0] = pq.peek()[0];
|
||||
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) { //如果堆顶元素不在滑动窗口内部,就移除 ,非堆顶元素不管
|
||||
|
||||
// 如果堆顶元素的下标不在当前窗口内,说明它已经滑出去了,弹出
|
||||
while (pq.peek()[1] <= i - k) {
|
||||
pq.poll();
|
||||
}
|
||||
|
||||
// 当前窗口的最大值就是堆顶元素的值
|
||||
ans[i - k + 1] = pq.peek()[0];
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
//单调队列
|
||||
|
||||
//单调队列(推荐)
|
||||
/**
|
||||
* 维护一个单调队列。
|
||||
在这个滑动窗口最大值的算法中,双端队列的两端各自承担不同的职责:
|
||||
@ -64,26 +88,44 @@ public class MaxSlidingWindow {
|
||||
*/
|
||||
public int[] maxSlidingWindow(int[] nums, int k) {
|
||||
int n = nums.length;
|
||||
Deque<Integer> deque = new LinkedList<>();
|
||||
Deque<Integer> deque = new LinkedList<>(); // 存放下标,维护一个单调递减队列(从队头到队尾)
|
||||
|
||||
// 1. 初始化前 k 个元素的单调队列
|
||||
for (int i = 0; i < k; ++i) {
|
||||
// 从队尾开始移除比当前元素小的元素下标,它们不可能成为后续最大值
|
||||
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
|
||||
deque.pollLast();
|
||||
}
|
||||
// 当前元素下标加入队尾
|
||||
deque.offerLast(i);
|
||||
}
|
||||
|
||||
// 2. 初始化结果数组(总共 n - k + 1 个窗口)
|
||||
int[] ans = new int[n - k + 1];
|
||||
// 当前窗口的最大值就是队头所指的下标对应的元素
|
||||
ans[0] = nums[deque.peekFirst()];
|
||||
|
||||
// 3. 开始滑动窗口:从第 k 个元素开始往右滑
|
||||
for (int i = k; i < n; ++i) {
|
||||
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { //队尾元素本来就比队头小,如果新元素比队尾还大,那就没有保留的价值了
|
||||
|
||||
// 维护队列的单调性:移除所有比当前元素小的队尾元素
|
||||
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
|
||||
deque.pollLast();
|
||||
}
|
||||
|
||||
// 把当前元素下标加入队尾
|
||||
deque.offerLast(i);
|
||||
|
||||
// 如果队头的下标已经滑出窗口左边,就移除它
|
||||
while (deque.peekFirst() <= i - k) {
|
||||
deque.pollFirst();
|
||||
}
|
||||
|
||||
// 队头就是当前窗口的最大值
|
||||
ans[i - k + 1] = nums[deque.peekFirst()];
|
||||
}
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,8 +16,26 @@ import java.util.HashMap;
|
||||
输入:nums = [1,2,3], k = 3
|
||||
输出:2
|
||||
*/
|
||||
|
||||
|
||||
//只会暴力解
|
||||
//二刷也是暴力解
|
||||
public class SubarraySum {
|
||||
public int subarraySum2(int[] nums, int k) {
|
||||
int[] prefix_sum=new int[nums.length+1];
|
||||
int cnt=0;
|
||||
prefix_sum[0]=0;
|
||||
for (int i = 1; i <= nums.length; i++) {
|
||||
prefix_sum[i]=nums[i-1]+prefix_sum[i-1];
|
||||
}
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
for (int j = i+1; j <= nums.length; j++) {
|
||||
if(prefix_sum[j]-prefix_sum[i]==k)
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
//枚举
|
||||
public int subarraySum(int[] nums, int k) {
|
||||
int count = 0;
|
||||
|
@ -11,7 +11,7 @@ public class SubarraySumTest {
|
||||
int[] nums={1,1,1};
|
||||
int k=2;
|
||||
SubarraySum solution = new SubarraySum();
|
||||
int cnt=solution.subarraySum(nums,k);
|
||||
int cnt=solution.subarraySum2(nums,k);
|
||||
System.out.println(cnt);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user