了解滑动窗口

前言:

大家好,我是Felix。 今天给大家带来一道经典的算法题,来了解一下动态窗口。加上这个,我们已经了解到了动态规划,贪心算法,积少成多嘛。

题意

科技馆内有一台虚拟观景望远镜,它可以用来观测特定纬度地区的地形情况。该纬度的海拔数据记于数组 <font style="color:rgba(38, 38, 38, 0.75);">heights</font> ,其中 <font style="color:rgba(38, 38, 38, 0.75);">heights[i]</font> 表示对应位置的海拔高度。请找出并返回望远镜视野范围 <font style="color:rgba(38, 38, 38, 0.75);">limit</font> 内,可以观测到的最高海拔值。

示例 1:

输入:heights = [14,2,27,-5,28,13,39], limit = 3
输出:[27,27,28,28,39]
解释:
  滑动窗口的位置                最大值
---------------               -----
[14 2 27] -5 28 13 39          27
14 [2 27 -5] 28 13 39          27
14 2 [27 -5 28] 13 39          28
14 2 27 [-5 28 13] 39          28
14 2 27 -5 [28 13 39]          39

好的,其实,题意还是很清晰的,就是这个望远镜在滑动的过程中,能够看到的最远高度的一个数组。


解法一

我们首先能够想到的就是暴力穷举,其实,这个大家每次都可以试一试,有助于我们更加深入的了解题意。

代码如下,还是很好理解的,但是要注意下对于数组工具类的灵活运用。

public static int[] maxAltitude(int[] heights, int limit) {
        // 首先要考虑极端条件,养成好习惯
        if (null == heights || heights.length == 0) return null;

        // 创建一个结果数组
        int[] dp = new int[heights.length - limit + 1];

        // 对于dp数组进行循环获取每次最大的值
        for (int i = 0;i < dp.length;i ++) {
            // 获取到每次望远镜中的数组
            int[] target = Arrays.copyOfRange(heights, i, i + limit);
            // 对数组进行排序
            Arrays.sort(target);
            // 去数组的最后以为作为结果
            dp[i] = target[limit - 1];
        }

        return dp;
    }

我们看下时间复杂度,结果数组循环O(n), 中间还使用了快速排序O(logn),所以最终的复杂度为两者的乘积,还是不太优的。那么有没有更好的解法呢?

解法二

其实,我们在刚才的循环过程中,有一些高度其实不用放到下次再去比较了,比如说第一组的【14, 2,27】移动到第二组【2,27, -5】的时候,这个2就不用再参与排序了,因为它肯定不会大过27,所以它可以排除掉的。

所以这个时候,要想到我们可以维护一个队列,并且是单调的队列,递减的,每次移动后,我们只需要拿到这个队列的第一个数,那就是我们想要的结果,听着有点抽象。看下代码的注释。


public static int[] maxAltitude(int[] heights, int limit) {
    // 边界条件
    if(heights.length == 0 || limit == 0) return new int[0];
    Deque<Integer> deque = new LinkedList<>();
    int[] res = new int[heights.length - limit + 1];
    // 未形成窗口
    for(int i = 0; i < limit; i++) {
        // 如果说队列空的,或者后面一个数要大于队列的最后一个数,那就移除最后一个,保证单调性
        while(!deque.isEmpty() && deque.peekLast() < heights[i])
            deque.removeLast();
        deque.addLast(heights[i]);
    }

    res[0] = deque.peekFirst();
    // 形成窗口后
    for(int i = limit; i < heights.length; i++) {
        // 这里的判断比较关键,比如说你在取结果集的res[1]的时候,如果这时候队列里的第一个元素是
        // 原始数组的hegihts[0],那么你是不能取的,因为第二次的望远镜中不包括第0个
        if(deque.peekFirst() == heights[i - limit])
            deque.removeFirst();
        while(!deque.isEmpty() && deque.peekLast() < heights[i])
            deque.removeLast();
        deque.addLast(heights[i]);
        res[i - limit + 1] = deque.peekFirst();
    }
    return res;
}



好的,今天的算法就到这里啦,大家如果有疑问,可以留言哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值