首页 > 试题广场 >

滑动窗口的最大值

[编程题]滑动窗口的最大值
  • 热度指数:581430 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个长度为 n 的数组 num 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。

例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

窗口大于数组长度或窗口长度为0的时候,返回空。

数据范围: ,数组中每个元素的值满足 
要求:空间复杂度 ,时间复杂度


示例1

输入

[2,3,4,2,6,2,5,1],3

输出

[4,4,6,6,6,5]
示例2

输入

[9,10,9,-7,-3,8,2,-6],5

输出

[10,10,9,8]
示例3

输入

[1,2,3,4],5

输出

[]
推荐
import java.util.*;
/**
用一个双端队列,队列第一个位置保存当前窗口的最大值,当窗口滑动一次
1.判断当前最大值是否过期
2.新增加的值从队尾开始比较,把所有比他小的值丢掉
*/
public class Solution {
   public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> res = new ArrayList<>();
       	if(size == 0) return res;
		int begin;	
		ArrayDeque<Integer> q = new ArrayDeque<>();
		for(int i = 0; i < num.length; i++){
			begin = i - size + 1;
			if(q.isEmpty())
				q.add(i);
			else if(begin > q.peekFirst())
                q.pollFirst();
		
			while((!q.isEmpty()) && num[q.peekLast()] <= num[i])
                q.pollLast();
			q.add(i);	
			if(begin >= 0)
				res.add(num[q.peekFirst()]);
		}
		return res;
    }
}

编辑于 2015-09-02 14:11:26 回复(51)
import java.util.*;

public class Solution {
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        ArrayList<Integer> dp = new ArrayList<>();
        if(size>num.length||size==0) return dp;
     for(int i=0;i<num.length-size+1;i++){
        int max = num[i];
        for(int j=1;j<size;j++){
            if(num[i+j]>max){
                max = num[i+j];
            }
        }
        dp.add(max);
     }
     return dp;
    }
}
编辑于 2024-03-28 20:50:46 回复(0)
略微优化的暴力求解。记录最大值在窗口内的位置。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num int整型一维数组 
     * @param size int整型 
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        // write code here
        ArrayList<Integer> list = new ArrayList<>();
        int max = 0;
        int count = 0;
        if(num.length ==0 || size > num.length || size ==0) return list;
        for(int i = 0;i<=num.length-size;i++){
            count--;
            if(count < 0){
                max = num[i];
                count = 0;
                for(int j = 1; j<size;j++){
                    if(num[i+j]> max){
                        max = num[i+j];
                        count = j;
                    }
                }
            }else{
                if(num[i+size-1] > max){
                    max = num[i+size-1];
                    count = size-1;
                }
            }
            list.add(max);
        }
        return list;
    }
}


编辑于 2024-01-29 16:34:43 回复(0)
//java双指针解法
import java.util.*;


public class Solution {
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        //定义内指针
        int i = 0;
        //定义外指针
        int j = 0;
        //记录最大值
        int max = 0;
        //初始化ArrayList来储存结果
        ArrayList<Integer> arr  = new ArrayList<>();
        //如果数组长度小于size或者size为0返回空
        if (num.length<size||size==0) return arr;
        //外指针需要遍历的次数为数组长度-size+1
        for (int index = 0;index< num.length-size+1;index++) {
            //每次将最大值初始化为当前滑块的第一个值
            max = num[i];
            //内循环,遍历滑块中的每一个数
            while (i<size+j-1){
                i++;
                //找到最大值
                if (max<num[i]){
                    max = num[i];
                }
            }
            //遍历完成后外循环指针加1
            j++;
            //将最大值添加到结果中
            arr.add(max);
            //每次循环完成一个滑块后将内指针i的位置移到下一个滑块的第一个位置上
            i = j;
        }
        return arr;
    }
}

编辑于 2024-01-08 14:47:21 回复(0)
为啥这个题目标记成了困难。我觉得很简单啊。从头遍历指定长度的字数组,拿到每个子数组的最大值,然后就ok了啊
发表于 2023-12-15 21:10:51 回复(1)
public class Solution {
    /**
     * 给定一个长度为 n 的数组 num 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。
     *
     * 双端队列保存最大值的下标
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        ArrayList<Integer> result = new ArrayList<>();
        if (size > num.length || size == 0) {
            return result;
        }
        ArrayDeque<Integer> que = new ArrayDeque<>();
        que.offerFirst(0);
        for (int i = 0; i < num.length; i++) {
            //当前元素比头更大,队列清空,保存下标
            if (num[i] >= num[que.peekFirst()]) {
                que.clear();
                que.offerFirst(i);
            }
            //比头小,也比尾小,下标置尾
            else if (num[i] < num[que.peekLast()]) {
                que.offerLast(i);
            }
            //比头小,比尾大,删除原来的尾部,再下标置尾
            else {
                que.pollLast();
                que.offerLast(i);
            }
            //检查下标元素是否在窗口,不在,则头部下标移除
            if (que.peekFirst() <= i - size) {
                que.pollFirst();
            }
            //窗口饱和开始记录最大值
            if (i >= size - 1) {
                result.add(num[que.peekFirst()]);
            }
        }
        return result;
    }

}

发表于 2023-10-30 13:11:02 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        int i = 0;
        int j = i + size - 1;
        int preMaxIndex = -1, maxIndex = -1;
        int preMax = Integer.MIN_VALUE, max = Integer.MAX_VALUE;
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int index = i; index <= j && j < num.length; index++) {
            if (maxIndex >= i && maxIndex <= j) {
                if (num[j] > max) {
                    max = num[j];
                    maxIndex = j;
                }
                arrayList.add(max);
                index = ++i - 1;
                j++;
                continue;
            } else if ((maxIndex < i || maxIndex > j) && index == i) {
                preMax = Integer.MIN_VALUE;
            }
            if (preMax < num[index]) {
                preMax = num[index];
                preMaxIndex = index;
            }
            if (index == j) {
                max = preMax;
                maxIndex = preMaxIndex;
                arrayList.add(max);
                index = ++i - 1;
                j++;
            }
        }
        return arrayList;
    }
}

发表于 2023-10-26 06:09:00 回复(0)
public static ArrayList<Integer> maxInWindows(int[] num, int size) {
        int left = 0;
        int right = size - 1;
        ArrayList<Integer> temp = new ArrayList<>();
        ArrayList<Integer> ret = new ArrayList<>();
        while (right < num.length) {
            for (int i = 0; i < size; i++) {
                temp.add(num[left]);
                left++;
                right++;
            }
            Optional<Integer> max = temp.stream().max(Integer::compareTo);
            max.ifPresent(ret::add);
            left = left - size + 1;
            right = right - size + 1;
            temp = new ArrayList<>();
        }
        return ret;
    }


发表于 2023-10-09 11:07:32 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num int整型一维数组 
     * @param size int整型 
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] nums, int k) {
        // 1. 参数判断
        if(k <= 0) {
            return new ArrayList<>();
        }
        if(nums.length < k) {
            return new ArrayList<>();
        }
        // 2. 创建滑动窗口最大值的数组
        // 长度为 nums.length - k + 1
        ArrayList<Integer> ans = new ArrayList<>();

        // 3. 定义左右窗口
        int L = 0;// 左窗口
        int R = 0;// 右窗口

        // 4. 创建双端队列来保存区间内的最大值
        LinkedList<Integer> queue = new LinkedList<>();

        // 5. 右窗口往右移动,添加元素
        for(R = 0;R < nums.length;R++) {
            // 6. 如果双端队列没有元素,直接添加
            // 如果双端队列有元素,还要判断队尾的值是否小于等于滑动窗口右侧的值,因为我们要保证双端队列要从大到小排列
            while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[R]) {
                queue.pollLast();
            }

            // 7. 添加元素到双端队列
            // 注意:添加到双端队列的是对应的下标
            queue.addLast(R);

            // 8. 更新双端队列头部的值
            if(queue.peekFirst() == R - k) {
                queue.pollFirst();
            }

            // 9. 添加结果到答案数组中
            // 当 R 来到了第三个位置的时候,就形成了长度为 3 的滑动窗口,此时就可以记录最大值了
            if(R >= k - 1) {
                ans.add(nums[queue.peekFirst()]);
            }
        }

        return ans;
    }
}

发表于 2023-09-10 09:59:46 回复(0)
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        // write code here
        int len = num.length;
        if (size > len || size == 0) {
            return new ArrayList<>();
        }
        int l = 0;
        int r = size;
        int max = Integer.MIN_VALUE;
        for (int i = l; i < r; i++) {
            max = Math.max(max, num[i]);
        }
        ArrayList<Integer> res = new ArrayList<>();
        res.add(max);
        while (r < len) {
            // 移除最大元素,就判断移入的是否最大,如果是就直接更新最大元素,否则循环查找最大元素
            if (num[l] == max) {
                if (num[r] >= max) {
                    max = num[r];
                } else {
                    max = Integer.MIN_VALUE;
                    for (int j = l + 1; j <= r; j++) {
                        max = Math.max(max, num[j]);
                    }
                }
            // 移除的元素不是最大元素,只需要判断移入的是否是大于最大元素,是更新,不是无操作
            } else {
                if (num[r] >= max) {
                    max = num[r];
                }
            }
            res.add(max);
            l++;
            r++;
        }

        return res;
    }
}
发表于 2023-08-14 17:24:02 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        // write code here
        ArrayList<Integer> res = new ArrayList<Integer>();
        if (size > num.length || size == 0) return res;
        for (int i = 0; i <= num.length - size; i++) {
            Stack<Integer> max = new Stack<Integer>();
            for (int j = i; j  < i + size; j++) {
                int temp = num[j];
                if (max.isEmpty() || (max.peek() < num[j])) {
                    max.push(num[j]);
                } else {
                    max.push(max.peek());
                }
            }
            res.add(max.peek());
        }
        return res;
    }
}

发表于 2023-08-12 16:46:20 回复(0)
//极其简单的写法
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        // write code here
        //计算出返回数组的长度
        int rtnNum=num.length-size+1;
       
        //先行条件
        ArrayList myrtnG=new ArrayList<Integer>(rtnNum);
        if(size>num.length||size==0){
            return myrtnG;
        }
       

       int max=0;
        //根据窗口大小设置循环
        for(int i=0;i<rtnNum;i++){
             max=0;
            for(int s=i;s<size+i;s++){

                if(num[s]>max){
                    max=num[s];
                }

            }
            myrtnG.add(max);
        }
        return myrtnG;
    }
}
发表于 2023-08-04 11:33:14 回复(0)
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param num int整型一维数组
     * @param size int整型
     * @return int整型ArrayList
     */
    public ArrayList<Integer> maxInWindows (int[] num, int size) {
        ArrayList<Integer> list = new ArrayList<>();
        if(num.length==0||size==0){
            return list;
        }
        for(int i=0;i<=num.length-size;i++){
            List<Integer> window = new ArrayList<>();
            for(int j=i;j<size+i;j++){
                window.add(num[j]);
            }
            Collections.sort(window);
            list.add(window.get(window.size()-1));
        }
        return list;
    }
}

发表于 2023-07-31 17:08:19 回复(0)
public ArrayList<Integer> maxInWindows (int[] num, int size) {
       
        // A进入窗口时,依次从尾部排除掉小于A的值
        // 窗口每次移动,从队首弹出窗口最前面的值
        //即将进入的值>窗口末尾值  那就一直弹出窗口末尾值,再加进去
        //当前窗口大于窗口距离,弹出队首
        //养窗口,当i>size,先在ans中放队列的队首值
        //队首始终是最大值
        Deque<Integer> qu=new LinkedList<>();//存的是索引下标
        ArrayList<Integer> ans=new ArrayList<>();
         if(num==null||size==0) return ans;
        for(int i=0;i<num.length;i++){//遍历元素中养窗口
        //Last()最后一个元素
        //First()第一个元素
            while(!qu.isEmpty()&&num[i]>num[qu.peekLast()]){//当前值>nums[索引]
                qu.pollLast();  //删掉的都是队尾元素
            }
            while(!qu.isEmpty()&&(i-qu.peekFirst()>=size)){//i-First()算窗口距离  >size,划出队的第一个元素
                qu.pollFirst();//删掉队头元素
            }
            qu.add(i);
            if(i>=size-1){//当i大于当前窗口值  (size-1是因为这里是从i是从0开始计数的)
                ans.add(num[qu.peekFirst()]);  //加入结果集的都是队头元素
            }
        }
        return ans;
    }

发表于 2023-07-19 14:41:51 回复(1)
import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        if (size > num.length || size == 0) {
            return list;
        }
        for (int i = 0; i <= num.length-size; i++) {
            int[] subArr = Arrays.copyOfRange(num, i, i + size);
            int asInt = Arrays.stream(subArr).max().getAsInt();
            list.add(asInt);
        }
        return list;
    }
}

发表于 2023-06-15 13:10:59 回复(0)
import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {

        ArrayList<Integer> list = new ArrayList<>();
        //窗口大于数组长度或窗口长度为0的时候,返回空
        if (size == 0 || size > num.length) {
            return list;
        }

        for (int i = 0; i < num.length; i++) {
            //判断当前坐标的最大位置,超过了,则直接跳过循环
            if (i + size > num.length) {
                continue;
            } else {
                //取出的窗口里面的值,后面用于排序
                ArrayList<Integer> sort = new ArrayList<>();
                for (int a = i; a < i + size; a++) {
                    sort.add(num[a]);
                }
                //排序
                Collections.sort(sort);
                //取出当前窗口最大的值
                list.add(sort.get(sort.size() - 1));
            }
        }
        return list;
    }
}

发表于 2023-06-06 17:25:49 回复(0)
import java.util.*;
public class Solution {
    //暴力就完事了
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        ArrayList<Integer> arr = new ArrayList<>();
        if(size>num.length||size==0) return arr;
        for(int i=0;i<=num.length-size;i++){
            int max=Integer.MIN_VALUE;
            for(int j=i;j<i+size;j++){
                if(num[j]>max) max=num[j];
            }
            arr.add(max);
        }
        return arr;
    }
}

发表于 2023-05-11 15:26:23 回复(0)
使用数组模拟单调队列(int q[], head, rear)
import java.util.*;
/**
 * 使用数组模拟单调队列(int q[], head, rear),注意 q[] 存储的是下标
 * 另一种做法是双端队列 ArrayDeque<Integer>
 */
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        if (size > num.length || size == 0) return new ArrayList<Integer>();
        int[] q = new int[10008];
        int n = num.length, head = 0, rear = 0;
        ArrayList<Integer> res = new ArrayList<>();
        q[head] = 0;
        for (int i = 0; i < n; i++) {
            // q[] 为单调递减队列,队头为窗口内的最大值
            while (head <= rear && num[q[rear]] < num[i]) rear--;
            q[++rear] = i;
            // 队头超出窗口的范围
            while (head <= rear && i - q[head] + 1 > size) head++;
            if (i >= size-1) res.add(num[q[head]]);
        }
        return res;
    }
}


发表于 2023-04-30 14:46:18 回复(0)
/*//方法一:暴力破解法
import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        ArrayList<Integer> res = new ArrayList<>();
        if(size==0 || size>num.length){
            return res;
        }
        for(int i=size;i<=num.length;i++){
            int max = find(num,i-size,i);
            res.add(max);
        }
        return res;
    }
    public int find(int[] num, int l, int r){
        int max = num[l];
        for(int i=l;i<r;i++){
            if(max < num[i]){
                max = num[i];
            }
        }
        return max;
    }
}*/

//方法二 双端队列
import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        //窗口长度不符合的情况
        ArrayList<Integer> res = new ArrayList<>();
        if (size == 0 || size > num.length) {
            return res;
        }
        //双端队列 存放数值的下标。当遍历的数值比队列末尾大,则末尾弹出【即在它前面比他小的都无用】,否则放入数值。
        //如果队列开头数值超过了窗口的范围则从头部弹出。并存放进结果集中。
        Deque<Integer> q = new ArrayDeque<>();
        //先遍历第一个窗口
        for (int i = 0; i < size; i++) {
            while (!q.isEmpty() && num[q.peekLast()] < num[i]) {  //前面小的不用保留
                q.pollLast();
            }
            q.add(i);
        }
        //继续遍历
        for (int i = size; i < num.length; i++) {
            //先把队列开头最大值存放进结果集中
            res.add(num[q.peekFirst()]); 
            //判断窗口是否出界
            if (!q.isEmpty() && q.peekFirst() < (i - size + 1)) {
                q.pollFirst();
            }
            //继续往双端队列中存放
            while (!q.isEmpty() && num[q.peekLast()] < num[i]) {
                q.pollLast();
            }
            q.add(i);
        }
        //把最后一个窗口的最大值存放进结果集中
        res.add(num[q.peekFirst()]);
        return res;
    }
}

发表于 2023-03-24 21:14:23 回复(0)