文章目录
手写数组大根堆
这道题 也直接验证了我的想法:对于二维数组来说,如果想要交换两个数组的内容的话,只要改变指针的指向即可,例如:
int[] tem = heapArr[cur];
heapArr[cur] = heapArr[parent];
heapArr[parent]= tem;
对一维数组适用吗?
自己有时间试一下
代码:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
PriorityQueue<Integer> q = new PriorityQueue<>((o1, o2) -> o1 - o2);{
class heap{
int size = 0;
int[][] heapArr;
private heap(int capacity){ // 不要用 size ,easy 混淆,之前就错在,多写了一句 this.size = size;
this.heapArr = new int[capacity+1][2];
}
public boolean add(int[] numsi){
if(size > heapArr.length){
return false;
}
heapArr[++size] = numsi;
up(size);
return true;
}
private void up(int cur){
while((cur>>1) >= 1){
int parent = cur>>1;
if( heapArr[parent][0] < heapArr[cur][0] ){
int[] tem = heapArr[cur];
heapArr[cur] = heapArr[parent];
heapArr[parent]= tem;
cur = parent;
}else{
break;
}
}
}
public int[] pop(){
int[] returnVal = heapArr[1];
heapArr[1] = heapArr[size];
size--;
Down(size);
return returnVal;
}
private void Down(int size){
int cur = 1;
while((cur<<1) <= size){
int child = cur<<1;
if((child+1) <= size && heapArr[child+1][0] > heapArr[child][0]){
child++;
}
if( heapArr[cur][0] < heapArr[child][0]){ // 55行
int[] tem = heapArr[cur];
heapArr[cur] = heapArr[child];
heapArr[child] = tem;
cur = child;
}else{
break; // 怎么少了break呢,太大意
}
}
}
public int[] peek(){
return heapArr[1];
}
}//end class heap
if(nums.length == 0 || k == 1){
return nums;
}
int[] res = new int[nums.length - k +1];
heap myheap = new heap(nums.length+1);
for(int i=0; i<k; i++){
myheap.add(new int[]{nums[i],i});
}
res[0] = myheap.peek()[0];
for(int i=k; i<nums.length; i++){
myheap.add(new int[]{nums[i],i});
if(nums[i] > myheap.peek()[0]){
res[i-k+1] = nums[i];
}else{
while(myheap.peek()[1] <= i-k ){
myheap.pop();
}
res[i-k+1] = myheap.peek()[0];
}
}
return res;
}
}
}
思路
首先要遍历一下第一个滑动窗口内的所有元素,找出第一个滑动窗口内的最大值
然后:
// 欲求当前窗口里的最大值,
// 就要先判断:
// a. 新加入的值 是否比上一个窗口最大值大,若是,则当前窗口里的最大值即:新加入的值
// b. 否则再判断:待移除的值 是否是上一个窗口的最大值,若不是,则当前窗口里的最大值即:上一窗口最大值
// c. 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值
题目
代码及注释
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//首先要遍历一下第一个窗口内的所有元素,找出第一窗口内的最大值
//然后:
// 欲求当前窗口里的最大值,
// 就要先判断:
// a. 新加入的值 是否比上一个窗口最大值大,若是,则当前窗口里的最大值即:新加入的值
// b. 否则再判断:待移除的值 是否是上一个窗口的最大值,若不是,则当前窗口里的最大值即:上一窗口最大值
// c. 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值
if (k == 0) return new int[0];
int res[] = new int[nums.length - k + 1]; // 记录每一窗口的最大值
for (int i = 0; i + k - 1 < nums.length; i++) { // i 代表当前正在求第 i 个滑动窗口内的最大值,res[1] 保存的是第一个滑动窗口内的最大值。res[2]是第二个窗口内的最大值
// 第 i 层循环的作用就是 求第 i 个滑动窗口内的最大值(从第0个滑动窗口开始) 。
if (i > 0 && nums[i-1 + k] > res[i-1]) // res[i-1]为上一个滑动窗口内的最大值,i-1+k即向后再走k步就走到了要判断的新值的位置。 新值比上一窗口最大值大,返回 新值
res[i] = nums[i-1 + k];
else if (i > 0 && nums[i - 1] < res[i - 1]) // 若新值比上一窗口最大值小 且 待移除窗口的值比上一窗口最大值小(即 被移出窗口的不是上个窗口的最大值),则当前窗口的最大值 就是 上一个窗口的最大值
res[i] = res[i - 1];
else { // 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值(下标从第 i 到 第 i+k-1 )
int max = Integer.MAX_VALUE + 1; // MAX_VALUE + 1 就取到了Integer范围内的 最小值,不是最大值哦
for (int j = i; j <= i + k -1; j++) {
max = Math.max(max, nums[j]);
res[i] = max; // 第一轮循环时:遍历前k个元素,找出第一个窗口里的最大值, 以k=3 为例,res[0] 保存着前3个数中的最大数
}
}
}
return res;
}
}
笨方法 (通过双端队列Deque自己通过while循环实现一个递增的单调队列)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 0 || k==0){
return new int[0];
}
int[] res = new int[nums.length - k + 1];
Deque<Integer> deq = new LinkedList<>();
for(int i =0 ; i < k ; i++){
while(!deq.isEmpty() && nums[i] > deq.peekLast()){
deq.removeLast();
}
deq.addLast(nums[i]);
}
int index = 0;
res[index++] = deq.peekFirst();
for(int i = k; i< nums.length; i++){
if( !deq.isEmpty() && deq.peekFirst() == nums[i-k]){ // 这一轮要滚出滑动窗口的元素nums[i-k] 就是该窗口的最大值
deq.removeFirst();
}
while (( !deq.isEmpty() && nums[i] > deq.peekLast())){ // 通过移出比新加入窗口的元素 小的元素, 找到新加入窗口的元素应该在的位置
deq.removeLast();
}
deq.addLast(nums[i]); // 在这位置加入 新加入窗口的元素
res[index++] = deq.peekFirst(); // 保存这一个串口的最大值(即对首元素)
}
return res;
}
}