【剑指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_919. Complete Binary Tree Inserter
https://leetcode.com/problems/complete-binary-tree-inserter/ 设计一个CBTInserter,使用给定完全二叉树初始化.三个功能; CBTI ...
- 关于nested exception is org.apache.ibatis.binding.BindingException:Parameter '***' not found报错解决
几天晚上遇到的奇怪的问题 传入的参数名一直没有变 但是从mapper到xml似乎有一个找不到参数的报错,实际上只要在Mapper接口形参前加“@Param(“形参名称”)”就可以了
- 色码表 Color code table
最近打算更新设计博客页面,需要用到CSS色码表,查了一些资料现转载此处以备以后使用,点击此处查看原文,另外还发现了几个不错的网站: color-hex HTML颜色代码 色碼表 色碼表英文為 Colo ...
- 看完这篇 你就能完全操作git 远程分支的增、删、改、查了
最近项目中又用到了git所以在此总结一番,这篇主要针对的是怎么创建远程分支,如何删除远程分支. 首先,如何创建远程分支.将一系列前期准备工作准备完成后(创建\添加ssh): 在终端键入 git bra ...
- yii1框架,事务使用方法
Yii1框架事务操作方法如下: $transaction= Yii::app()->db->beginTransaction();//创建事务 $transaction->commi ...
- Yii 2.0版本调试输出SQL语句
项目是基于框架Yii 2.0开发的. 今天梳理一些数据统计功能代码的时候,想把当前运行的sql语句打印出来,然后放到navicat工具里面运行,并分析一下运行效率和调优方案,之前大部分时候都是写增加. ...
- CentOS7安装Tomcat9并设置开机启动
1.下载 Tomcat 9 CentOS 7 下创建目录并下载文件: cd /usr/local/ mkdir tomcat cd tomcat wget http://mirrors.hust.ed ...
- Python面向对象之类属性类方法静态方法
类的结构 实例 使用面向对象开发时,第一步是设计类: 当使用 类名() 创建对象时,会自动执行以下操作: 1.为对象在内存中分配空间--创建对象: 2.为对象的属性 设置初始值--初始化方法(init ...
- UVA 140 Bandwidth (dfs 剪枝 映射)
题意: 给定一个n个结点的图G和一个结点的排列, 定义结点i的带宽b(i)为i和相邻结点在排列中的最远距离, 所有b(i)的最大值就是这个图的带宽, 给定G, 求让带宽最小的结点排列. 给定的图 n ...
- Python接口测试之unittest框架(五)
Test-driven development(TDD)开发模式在今天已经不是什么新奇的事了,它的开发思维是在开发一个产品功能的时候,先 编写好该功能的测试代码,在编写开发比如,比如要写二个数相除的函 ...