【剑指Offer学习】【面试题65:滑动窗体的最大值】
题目:给定一个数组和滑动窗体的大小,请找出全部滑动窗体里的最大值。
举例说明
比如,假设输入数组{2,3,4,2,6,2,5,1}及滑动窗体的大小。那么一共存在6个滑动窗体,它们的最大值分别为{4,4,6,6,6,5}。
解题思路
假设採用蛮力法,这个问题似乎不难解决:能够扫描每个滑动窗体的全部数字并找出当中的最大值。假设滑动窗体的大小为k,须要O(k)时间才干找出滑动窗体里的最大值。对于长度为n的输入数组,这个算法总的时间复杂度是O(nk)。
实际上一个滑动窗体能够看成是一个队列。当窗体滑动时,处于窗体的第一个数字被删除,同一时候在窗体的末尾加入一个新的数字。
这符合队列的先进先出特性。
假设能从队列中找出它的最大数,这个问题也就攻克了。
在面试题21中。我们实现了一个能够用O(1)时间得到最小值的栈。相同,也能够用O(1)时间得到栈的最大值。同一时候在面试题7中,我们讨论了怎样用两个栈实现一个队列。
综合这两个问题的解决方法,我们发现假设把队列用两个栈实现,因为能够用O(1)时间得到栈中的最大值。那么也就能够用O(1)时间得到队列的最大值,因此总的时间复杂度也就降到了O(n)。
我们能够用这种方法来解决这个问题。
只是这样就相当于在一轮面试的时间内要做两个面试题,时间未必够用。再来看看有没有其他的方法。
以下换一种思路。我们并不把滑动窗体的每个数值都存入队列中,而仅仅把有可能成为滑动窗体最大值的数值存入到一个两端开口的队列。接着以输入数字{2,3,4,2,6,2,5,1}为例一步分析。
数组的第一个数字是2,把它存入队列中。第二个数字是3.因为它比前一个数字2大,因此2不可能成为滑动窗体中的最大值。
2先从队列里删除,再把3存入到队列中。此时队列中仅仅有一个数字3.针对第三个数字4的步骤相似,终于在队列中仅仅剩下一个数字4.此时滑动窗体中已经有3个数字。而它的最大值4位于队列的头部。
接下来处理第四个数字2。2比队列中的数字4小。当4滑出窗体之后2还是有可能成为滑动窗体的最大值,因此把2存入队列的尾部。
如今队列中有两个数字4和2,当中最大值4仍然位于队列的头部。
下一个数字是6.因为它比队列中已有的数字4和2都大,因此这时4和2已经不可能成为滑动窗体中的最大值。先把4和2从队列中删除。再把数字6存入队列。这个时候最大值6仍然位于队列的头部。
第六个数字是2.因为它比队列中已有的数字6小,所以2也存入队列的尾部。此时队列中有两个数字,当中最大值6位于队列的头部。
接下来的数字是5.在队列中已有的两个数字6和2里。2小于5。因此2不可能是一个滑动窗体的最大值,能够把它从队列的尾部删除。删除数字2之后,再把数字5存入队列。此时队列里剩下两个数字6和5,当中位于队列头部的是最大值6.
数组最后一个数字是1。把1存入队列的尾部。注意到位于队列头部的数字6是数组的第5个数字,此时的滑动窗体已经不包含这个数字了,因此应该把数字6从队列删除。那么怎么知道滑动窗体是否包含一个数字?应该在队列里存入数字在数组里的下标,而不是数值。当一个数字的下标与当前处理的数字的下标之差大于或者等于滑动窗体的大小时。这个数字已经从滑动窗体中滑出,能够从队列中删除了。
代码实现
import java.util.*;
public class Test65 {
private static List<Integer> maxInWindows(List<Integer> data, int size) {
List<Integer> windowMax = new LinkedList<>();
// 条件检查
if (data == null || size < 1 || data.size() < 1) {
return windowMax;
}
Deque<Integer> idx = new LinkedList<>();
// 窗体还没有被填满时。找最大值的索引
for (int i = 0; i < size && i < data.size(); i++) {
// 假设索引相应的值比之前存储的索引值相应的值大或者相等,就删除之前存储的值
while (!idx.isEmpty() && data.get(i) >= data.get(idx.getLast())) {
idx.removeLast();
}
// 加入索引
idx.addLast(i);
}
// 窗体已经被填满了
for (int i = size; i < data.size(); i++) {
// 第一个窗体的最大值保存
windowMax.add(data.get(idx.getFirst()));
// 假设索引相应的值比之前存储的索引值相应的值大或者相等。就删除之前存储的值
while (!idx.isEmpty() && data.get(i) >= data.get(idx.getLast())) {
idx.removeLast();
}
// 删除已经滑出窗体的数据相应的下标
if (!idx.isEmpty() && idx.getFirst() <= (i - size)) {
idx.removeFirst();
}
// 可能的最大的下标索引入队
idx.addLast(i);
}
// 最后一个窗体最大值入队
windowMax.add(data.get(idx.getFirst()));
return windowMax;
}
private static List<Integer> arrayToCollection(int[] array) {
List<Integer> result = new LinkedList<>();
if (array != null) {
for (int i : array) {
result.add(i);
}
}
return result;
}
public static void main(String[] args) {
// expected {7};
List<Integer> data1 = arrayToCollection(new int[]{1, 3, -1, -3, 5, 3, 6, 7});
System.out.println(data1 + "," + maxInWindows(data1, 10));
// expected {3, 3, 5, 5, 6, 7};
List<Integer> data2 = arrayToCollection(new int[]{1, 3, -1, -3, 5, 3, 6, 7});
System.out.println(data2 + "," + maxInWindows(data2, 3));
// expected {7, 9, 11, 13, 15};
List<Integer> data3 = arrayToCollection(new int[]{1, 3, 5, 7, 9, 11, 13, 15});
System.out.println(data3 + "," + maxInWindows(data3, 4));
// expected {16, 14, 12};
List<Integer> data5 = arrayToCollection(new int[]{16, 14, 12, 10, 8, 6, 4});
System.out.println(data5 + "," + maxInWindows(data5, 5));
// expected {10, 14, 12, 11};
List<Integer> data6 = arrayToCollection(new int[]{10, 14, 12, 11});
System.out.println(data6 + "," + maxInWindows(data6, 1));
// expected {14};
List<Integer> data7 = arrayToCollection(new int[]{10, 14, 12, 11});
System.out.println(data7 + "," + maxInWindows(data7, 4));
}
}
执行结果
特别说明
欢迎转载,转载请注明出处【http://blog.csdn.net/DERRANTCM/article/details/46872411】
【剑指Offer学习】【面试题65:滑动窗体的最大值】的更多相关文章
- 【剑指offer】面试题 65. 不用加减乘除做加法
面试题 65. 不用加减乘除做加法 题目描述 题目:写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. Java 实现 public class Solution { ...
- 《剑指offer》面试题65. 不用加减乘除做加法
问题描述 写一个函数,求两个整数之和,要求在函数体内不得使用 "+"."-"."*"."/" 四则运算符号. 示例: 输 ...
- 《剑指offer》面试题59 - II. 队列的最大值
问题描述 请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value.push_back 和 pop_front 的均摊时间复杂度都是O(1). 若队列为空,pop_ ...
- 【剑指Offer学习】【全部面试题汇总】
剑指Offer学习 剑指Offer这本书已经学习完了.从中也学习到了不少的东西,如今做一个总的文件夹.供自已和大家一起參考.学如逆水行舟.不进则退.仅仅有不断地学习才干跟上时候.跟得上技术的潮流! 全 ...
- 【剑指Offer学习】【所有面试题汇总】
剑指Offer学习 剑指Offer这本书已经学习完了,从中也学习到了不少的东西,现在做一个总的目录,供自已和大家一起参考,学如逆水行舟,不进则退.只有不断地学习才能跟上时候,跟得上技术的潮流! 所有代 ...
- 剑指Offer——滴滴笔试题+知识点总结
剑指Offer--滴滴笔试题+知识点总结 情景回顾 时间:2016.9.18 15:00-17:00 地点:山东省网络环境智能计算技术重点实验室 事件:滴滴笔试 总体来说,滴滴笔试内容体量不算多, ...
- 剑指Offer——网易笔试题+知识点总结
剑指Offer--网易笔试题+知识点总结 Fibonacci package cn.edu.ujn.nk; import java.util.ArrayList; import java.util.S ...
- 剑指Offer——咪咕笔试题+知识点总结
剑指Offer--咪咕笔试题+知识点总结 情景回顾 时间:2016.10.09 15:00-16:30 地点:山东省网络环境智能计算技术重点实验室 事件:咪咕笔试 知识点总结 1.Html设置格式贵阳 ...
- 剑指Offer——迅雷笔试题+知识点总结
剑指Offer--迅雷笔试题+知识点总结 情景回顾 时间:2016.9.19 19:00-21:00 地点:山东省网络环境智能计算技术重点实验室 事件:迅雷笔试 总体来说,迅雷笔试内容体量不算多,主要 ...
- 《剑指offer》面试题39 二叉树的深度(java)
摘要: 今天翻到了<剑指offer>面试题39,题目二中的解法二是在函数的参数列表中通过指针的方式进行传值,而java是没有指针的,所以函数要进行改造.然而我翻了下别人的java版本(我就 ...
随机推荐
- leetcode_865. Smallest Subtree with all the Deepest Nodes
https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/ 给定一颗二叉树,输出包含所有最深叶子结点的最小子树 ...
- Log4j 配置某个类中某个方法的输出日志到指定文件
我们在项目中使用log4j开发的时候,会遇到一些特殊的情况,比如:要输出某个类中某个方法的日志信息到文件中,方便以后查看 可以使用如下配置: log4j.rootLogger=info,stdout ...
- CAD使用GetxDataDouble读数据(com接口)
主要用到函数说明: MxDrawEntity::GetxDataDouble2 读取一个Double扩展数据,详细说明如下: 参数 说明 [in] LONG lItem 该值所在位置 [out, re ...
- 在SpringBoot框架中使用拦截器
1.继承WebMvcConfigureAdapter类,覆盖其addInterceptors接口,注册我们自定义的拦截器 package com.eth.wallet.config; import c ...
- Python列表、元组、字典、集合的内置使用方法
列表: 是一种可以存储多个值得数据容器 内容是有序的 可以存储任何数据类型 可以存储重复的元素 是可变类型(当内容发生变化时id不变) 元组: 也是一种可以存储多个值得数据容器 元组中的元素不可以被修 ...
- mysql explain的使用
一.explain返回各列的含义: 1.table:显示这一行的数据是关于那张表的 2.type:重要的列,显示连接使用了何种类型,从最好到最差的连接类型为const.eq_reg.ref.range ...
- Python:安装3.6
centos7 自带有 python,但是却是 python2 版本的 python,如果你想安装个python3怎么办呢?难道要从github上把源码clone下来进行编译安装么?没错!因为 yum ...
- Java 文件操作大集合
package com.sess.hny.sys.fileserver; import java.io.BufferedInputStream;import java.io.BufferedOutpu ...
- 测试Mysql悲观锁
- python 多线程并发threading & 任务队列Queue
https://docs.python.org/3.7/library/concurrency.htmlpython程序默认是单线程的,也就是说在前一句语句执行完之前后面的语句不能继续执行先感受一下线 ...