前言:
大家好,我是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;
}
好的,今天的算法就到这里啦,大家如果有疑问,可以留言哦