栈和队列的基础算法学习(EPI)
今天学习的时间虽然挺多的,但是总觉效率不高。其实今天没有按照计划进行EPI题目的浏览,白天去看了其他的书籍。准备找工作可能需要的状态是一定量经典的书,偶尔温习才可。书是看不完的,知识点也是固定的。所以从把手头的几本书在浏览完毕之后就要着手复习之前的知识啦。C++的知识,leetcode的题目,操作系统,数据库,网络的学习笔记~。
1. 实现一个栈,支持返回当前栈中最大值的操作。要求,返回最大值的操作时间复杂度O(1)。可以使用额外的O(n)的空间复杂度。
题目之前见到过,所以思路一下子就有了,利用额外的栈存储当前栈中最大值即可。
简单的思路,在元素入栈的时候,辅助栈同时压入当前栈的最大值,元素出栈的时候,弹出辅助栈的元素。取得最大值直接从辅助栈栈頂获取即可。
另外,可以减少一下压入辅助栈中的元素的数量,只有压入当前栈的元素大于等于当前辅助栈栈顶元素,才将该至压入辅助栈栈顶,出栈的时候,只有出栈元素等于辅助栈栈顶元素时,才将辅助栈栈顶弹出。
另外,能在常数项更优化的一个方法是,辅助栈中压入一个数对,数对的意义是当前的最大值,以及当前最大值的数量,push的时候如果相等,则增加数对的第二个值,pop的时候如果相等,减去数对中的第二个值,如果减至0,则pop辅助栈即可。
扩展问题,实现一个队列,支持返回当前最大值的操作,能否优化至O(1)的时间复杂度。

这个题目还是比较复杂的,需要结合两个知识来把时间复杂度均摊为O(1),及利用两个已经实现最大值操作的堆栈来模拟队列,可以达到均摊O(1)复杂度的返回最大值的队列。
其实利用deque也能够达到O(1)的均摊成本,但是时间复杂度分析比较复杂。

均摊的理解是每个元素最多进入D和离开D一次,不会第二次进入和离开D。所以入队的均摊O(1)。
2.实现逆波兰表达式的计算并返回计算结果。
利用栈不断的压入数字,遇到运算符号,从数字栈中取出两个数字进行计算,结果继续压入数字栈,直到计算完毕,数字栈中存储的运算结果。
3.迭代方法实现BST的中序遍历。
利用栈的迭代实现不是很复杂,而且可以完成O(1)空间复杂度的morris中序遍历。
而且迭代实现二叉树的遍历方法中,后序遍历的实现是难度最大的。morris的后序遍历实现起来难度也很大。
4.针对随机链表,即除了next域之外,增加一个random指针域的链表,迭代的方法进行random-first序的遍历。
递归的方法比较容易实现,这里让进行迭代即利用stack来模拟递归的方法即可。
template <typename T>
void search_postings_list(const shared_ptr<node_t<T> > &L) {
stack<shared_ptr<node_t<T> > > s;
int order = 0;
s.emplace(L);
while(!s.empty()) {
shared_ptr<node_t<T> > curr = s.top();
s.pop();
if( curr && curr->order == -1 ) {
curr->order = order++;
s.emplace(curr->next);
s.emplace(curr->jump);
}
}
}
5.利用栈记录汉诺塔的移动过程,模拟。
void transfer(const int &n, array<stack<int>,3> &pegs, const int &from, const int & to, const int &use) {
if(n > 0) {
transfer(n-1,pegs,from,use,to);
pegs[to].push(pegs[from].top());
pegs[from].pop();
cout<<"Move from peg"<<from<<"to peg"<<to<<endl;
transfer(n-1,pegs,use,to,from);
}
}
void move_tower_hanoi(const int &n) {
array<stack<int>,3> pegs;
for(int i = n;i >= 1;--i) {
pegs[0].push(i);
}
transfer(n,pegs,0,1,2);
}
6.一排楼房所有的窗户都面朝西,太阳落下的时候如果一个楼房的西面不存在比该楼房高的楼房,则该楼房可以看到阳光,从东至西计算出所有可以看到阳光的楼房。
扩展问题:从西至东计算出所有可以看到阳光的楼房。
问题的根本思路是利用栈,从东至西维护一个递减的序列。从西至东则需要维护一个递增的序列。其中序列的内容及为可看到阳光的楼房。这种利用栈维护单调序列的方法在求最大直方图面积中应用可以减少时间复杂度至O(n)。
从东至西的递减序列code
template <typename T>
vector<pair<int,T>> examine_buildings_with_sunset(istringstream &sin) {
int idx = 0;//building's index
T height;
//Stores(buiding_idx,building_height) pair with sunset views
vector<pair<int,T> > buildings_with_sunset;
while(sin >> height) {
while(buildings_with_sunset.empty() == false && height >= buildings_with_sunset.back().second) {
buildings_with_sunset.pop_back();
}
buildings_with_sunset.emplace_back(idx++,height);
}
return buildings_with_sunset;
}
7.设计一个排序堆栈的算法仅仅利用push,pop,empty,top操作,并且不显示的开辟额外空间。
如果不显示的开辟额外空间,就想想利用函数递归调用的堆栈存储信息,这样就能够进行排序。比如插入排序的递归实现方法。
template <typename T>
void sort(stack<T> &S) {
if(!S.emtpy()) {
T e = S.top();
S.pop();
sort(S);
insert(S,e);
}
}
template <typename T>
void insert(stack<T> &S,const T &e) {
if(S.empty() || S.top() <= e) {
S.push(e);
}else {
T f = S.top();
S.pop();
insert(S,e);
S.push(f);
}
}
8.将包含..和.的文件路径名简化至最短路径。
思路就是保持一个栈,当遇到..的时候讲栈顶的目录名弹出,遇到.则忽略。这样就可以得到最短路径了。该题目边界情况较多,属于细节题。
9.层序遍历BST的方法。
层序遍历,即广度优先搜索,需要借助队列来完成功能。
10.利用两个整数实现一个队列的功能。队列中能够加入的元素为[0,9]。
首先看到这个题目想到的是将整数看成位数组,4位可以表示[0,15]之间的数字,所以可以当成数组。
后来参考答案看到按照十进制的位来表示[0,9]计算起来更加方便。刚好十进制的每位都是[0,9],一个数字作为数组,另外一个数字作为队列的长度。注意全为0的边界情况。
扩展问题:如果只有一个整数,可以使用其中一位保存长度。
11.利用两个栈实现一个队列,使得pop和push的均摊成本O(1)。
一个栈负责进入队列,另外一个栈负责弹出队列。
12.O(1)返回队列max值的队列的应用。
应用场景是现在有一个数组,数组是一个数对,第一个元素表示一个时间戳,第二个元素表示该事件的流量,数组已经根据时间戳有序的,现在需要计算每个时间戳至时间戳+w这段时间内的最大流量是多少。
如果直接解法则需要遍历当前时间戳的流量至当前时间戳+w这段时间内所有流量,时间复杂度O(nw)。
如果利用优先队列的话因为是最小堆实现的,所以可以优化至O(nlogw)的时间复杂度。
如果利用O(1)返回最大值的队列,则优化至了O(n)的时间复杂度。
栈和队列的基础算法学习(EPI)的更多相关文章
- [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...
- 用JS描述的数据结构及算法表示——栈和队列(基础版)
前言:找了上课时数据结构的教程来看,但是用的语言是c++,所以具体实现在网上搜大神的博客来看,我看到的大神们的博客都写得特别好,不止讲了最基本的思想和算法实现,更多的是侧重于实例运用,一边看一边在心里 ...
- 四旋翼基础算法学习2-IMU输入滤波算法
前言: 处理器读取陀螺仪加速度计数据后首先需要对数据进行滤波处理,此文分析比较几种常用的滤波算法. 参考学习:四轴加速度计滤波 IMU: IMU使用MPU9250(即MPU6500),设置加速度量程± ...
- 基础算法学习2-dp
一.算法题: 最大子阵 给定一个n×m 的矩阵 A,求A 中的一个非空子矩阵,使这个子矩阵中的元素和最大.其中,A 的子矩阵指在 A 中行和列均连续的一部分.输入格式输入的第一行包含两个整数 n,m( ...
- 基础算法学习以及$STL$的使用
1.优先队列 (1)大根堆(小顶堆) priority_queue<int,vector<int>,greater<int> >q; (2)小根堆(大顶堆) pri ...
- C++基础算法学习——逆波兰表达式问题
例题:逆波兰表达式逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3.逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 ...
- C++基础算法学习——N皇后问题
n皇后问题:输入整数n, 要求n个国际象棋的皇后,摆在n*n的棋盘上,互相不能攻击,输出全部方案. 代码如下: #include <iostream> #include<cmath& ...
- C++基础算法学习——汉洛塔问题
汉诺塔问题古代有一个梵塔,塔内有三个座A.B.C,A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图).有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中, ...
- C++基础算法学习——熄灯问题
有一个由按钮组成的矩阵, 其中每行有6个按钮, 共5行– 每个按钮的位置上有一盏灯– 当按下一个按钮后, 该按钮以及周围位置(上边, 下边,左边, 右边)的灯都会改变状态26熄灯问题 POJ1222– ...
随机推荐
- java 对象数组
java 对象数组 from zhaocundang@163.com 先 用类声明数组: 再把类的实例赋给数组: package works; import java.util.Scanner; pu ...
- java链接mysql 中文乱码
{转!} 背景: 由于最近在开发一个APP的后台程序,需要Java连接远程的MySQL数据库进行数据的更新和查询操作,并且插入的数据里有中文,在插入到数据库后发现中文都是乱码.网上查了很多教程,最后都 ...
- [MVC] 自定义ActionSelector,根据参数选择Action
很多时候我们会根据UI传入的参数,呈现不同的View.也就是对于同一个Action如何根据请求数据返回不同的View.通常情况下我们会按照如下方法来写,例如: [AcceptVerbs(HttpVer ...
- 关于android 内存的笔记
原文 https://developer.android.com/training/articles/memory.html 1.慎重使用Service,最好的办法是使用IntentService,一 ...
- 五步整理你的css文件
鉴于实在无法忍受那种写一句就换一行的css写法,有个项目中的一个css文件竟然高达6000多行,看着实在蛋疼,无实今天下定决心整理一下,在DW里可以用正则很好的进行替换,步骤如下: 一:\r => ...
- 基于NDK的Android防破解& Android防破解 【转载】
两篇防破解文章转载 基于NDK的Android防破解:http://blog.csdn.net/bugrunner/article/details/8634585 Android防破解:http:// ...
- 使用InternetGetConnectedState判断本地网络状态(C#举例)
函数原型:函数InternetGetConnectedState返回本地系统的网络连接状态. 语法: BOOL InternetGetConnectedState( __out LPDWORD lpd ...
- DATAGUARD的搭建
ORACLE Data Guard 理论知识 请查看此blog :http://blog.csdn.net/haibusuanyun/article/details/11519241 Oracle D ...
- Lua协程-测试2
print("Lua 协程测试2") function testFun(n) print("into foo,n = "..n) * n) -- 挂起co协程 ...
- Bypass ngx_lua_waf SQL注入防御(多姿势)
0x00 前言 ngx_lua_waf是一款基于ngx_lua的web应用防火墙,使用简单,高性能.轻量级.默认防御规则在wafconf目录中,摘录几条核心的SQL注入防御规则: select.+ ...