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