不得不说编程之美是一本好书,虽然很多题目在做acm中的过程中遇到过,不过还是有很多值得思考的地方

这是今天在编程之美上看到的一个问题,对于栈转化成队列的一个思考

平时都太过依赖c++内函数库中的栈和队列,但是对于他们的扩展我们还是应该自己进行手写栈和队列来实现更简单的算法

题目大意:

假设有这样一个拥有3个操作的队列:

1. EnQueue(v) : 将 v 加入队列

2. DeQueue: 使队列中队首元素删除并返回此元素

3.MaxElement: 返回队列中的最大元素

设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低

首先来思考这样一个问题:

对于前面已知的一段序列,我们加入一个元素x,得到当前序列的最大值会特别容易

maxVal[i] = max(maxVal[i-1] , x);

那么我们删掉第 i 个元素,得到的序列中的最大值也特别容易就是maxVal[i-1]

换个角度想想此时的第 i 个元素可理解为栈顶元素

也就是说这道题目改成拥有3个栈操作的队列那么我们直接就可以在单位时间内得到MaxElement

而保存这些数也就是把所有数扫一遍,O(N)就解决了

但是这里是队列,队列总是删去最前面也就是下标为 0 的元素,这样我们无法利用maxVal[i]来表示当前队列元素中的最大值

那我们可以考虑,既然栈如此方便,如何将队列用栈来表示

首先我们需要两个栈,把数据放入一个栈s2,那么这些数据其实是倒着保存的 , 那么我们要删去队列的首元素,也就是删除栈底的元素,

那么我们可以利用另一个栈s1,将前一个栈s2中的元素再倒一遍进入另一个栈s1,那么此时s1的栈顶也就是队列的栈顶

也就是说只要s1中有元素,那么s1中的栈顶始终是队列首元素

只有当s1中元素都不存在时,才将s2中的元素一次性全倒入s1

int DeQueue()
    {
        if(s1.empty() && s2.empty()) return -INF; //队列中值不存在
        if(s1.empty()){
            while(!s2.empty()){
                s1.push(s2.pop());
            }
        }
        return s1.pop();
    }

那么队列中的所有元素总是分布在s1和s2中,那么最大元素既可能在s1,也可能在s2中,所以返回 return max(s1.Max() , s2.Max());

这样这个程序总的复杂度就能够达到O(N)的线性复杂度了

接下来是自己手写的一个测试过的没有问题的程序

 #include <cstdio>
#include <cstring>
#include <exception>
using namespace std;
#define max(a,b) a>b?a:b
const int MAXN = ;
const int INF = 0x3fffffff;
struct Stack{
int top , a[MAXN] , maxVal[MAXN];
//a[]保存栈中的元素,maxVal[i]保存i以及前方的最大值,top为栈顶指针,初始为-1
Stack(){
top = -;
memset(maxVal , - , sizeof(maxVal));
}
void push(int x)
{
if(top>=MAXN) throw exception();
a[++top] = x;
if(top == ) maxVal[top]=x;
else maxVal[top] = max(maxVal[top-] , x);
}
bool empty(){return top == -;}
int Max()
{
if(empty()) return -INF;
return maxVal[top];
}
int pop()
{
if(top<) return -;
int ret = a[top--];
return ret;
}
}; struct Queue{
Stack s1 , s2;
Queue()
{
s1 = Stack();
s2 = Stack();
}
void EnQueue(int x)
{
s2.push(x);
}
int DeQueue()
{
if(s1.empty() && s2.empty()) return -INF; //队列中值不存在
if(s1.empty()){
while(!s2.empty()){
s1.push(s2.pop());
}
}
return s1.pop();
}
int MaxElement()
{
return max(s1.Max() , s2.Max());
}
bool empty()
{
return s1.empty()&&s2.empty();
}
}; int main()
{
// freopen("a.in" , "r" , stdin);
Queue q; q = Queue();
// int num[10] = {5 , 7 , 6 , 3 , 2 , 4 , 9 , 15 , 13 , 11};
q.EnQueue();
int op , x;
while(!q.empty())
{
printf("输入操作类型:");
scanf("%d" , &op);
if(op == ){
printf("输入一个数入队列:");
scanf("%d" , &x);
q.EnQueue(x);
}
else if(op == ){
printf("队列首元素 %d 从队列中退出\n" , q.DeQueue());
}
else{
printf("当前队列最大元素为 %d\n" , q.MaxElement());
} //下方每次用来检测队列中两个栈的数据保存情况
/*
printf("输出栈1中的元素\n");
for(int i=q.s1.top ; i>=0 ; i--){
printf("%d " , q.s1.a[i]);
}
puts(""); printf("输出栈2中的元素\n");
for(int i=q.s2.top ; i>=0 ; i--){
printf("%d " , q.s2.a[i]);
}
puts("");
*/
}
return ;
}

<<编程之美>> -- 队列中取最大值操作的问题的更多相关文章

  1. 编程之美 set 10 队列中取最大值操作问题

    题目 假设有这样一个拥有三个操作的队列 1. Enqueue(v) 2. Dequeue() 3. MaxEle() 请设计一种数据结构和算法, 让 MAXELE 操作的时间复杂度尽可能的低 思路 1 ...

  2. 在含有null值的复杂类的集合(Collection)中取最大值

    在日常编程中,经常遇到要在一组复杂类的集合(Collection)中做比较.取最大值或最小值. 举个最简单的例子,我们要在一个如下结构的集合中选取包含最大值的元素: public class Clas ...

  3. Java并发编程:阻塞队列(转载)

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  4. 【转】Java并发编程:阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  5. Java并发编程:阻塞队列 <转>

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  6. 12、Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  7. (转)Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  8. linux编程之消息队列

    消息队列是内核地址空间中的内部链表,通过linux内核在各个进程之间传递内容,消息顺序地发送到消息队列中,并且以几种不同的方式 从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识,内核中的消息 ...

  9. JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证

    这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...

随机推荐

  1. 448 Find All Numbers Disappeared in an Array 找到所有数组中消失的数字

    给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次.找到所有在 [1, n] 范围之间没有出现在数组中的数字.您能在不使用 ...

  2. jacaScript数组

    1.var arr=['1','2','3'] typeof arr (判断数组类型)    print(arr)打印数组内容 2.arr[100]='x',  数组中间自动添加,alert(arr. ...

  3. 实现php间隔一段时间执行一次某段代码

    <?php ignore_user_abort(); //即使Client断开(如关掉浏览器),PHP脚本也可以继续执行.  set_time_limit(0); // 执行时间为无限制,php ...

  4. [ BZOJ 2038 ] Hose

    \(\\\) Description 给出一个数列,多次询问,每次给出一个区间 \([l_i,r_i]\) ,问在区间中随意选两个位置不同的数,是同一个数的概率有多大. \(n,m\le 5\time ...

  5. 2017.5.20欢(bei)乐(ju)赛解题报告

    预计分数:100+20+50=first 实际分数:20+0+10=gg 水灾(sliker.cpp/c/pas) 1000MS  64MB 大雨应经下了几天雨,却还是没有停的样子.土豪CCY刚从外地 ...

  6. EL表达式、JSTL

    EL表达式 一.简介 > JSP表达式 <%= %> 用于向页面中输出一个对象.        > 到JSP2.0时,在我们的页面中不允许出现 JSP表达式和 脚本片段.   ...

  7. 微信小程序组件解读和分析:六、progress进度条

    progress进度条组件说明: 进度条,就是表示事情当前完成到什么地步了,可以让用户视觉上感知事情的执行.progress进度条是微信小程序的组件,和HTML5的进度条progress类似. pro ...

  8. linux 安装 mongo 3.4

    要求:linux 安装 mongo 3.4 大体上,按照官网提供的方法来做. 系统是ubuntu 16.04 安装的是mongo3.4.8 社区版 1.         导入导入包管理系统使用的公钥 ...

  9. maven多模块项目,多web合并项目使用心得

    Fixflow,做中国最好的开源流程引擎!项目地址https://github.com/fixteam/fixflow 此文章适合maven初学者或想接触maven的用户,讲的只是皮毛,高手请自觉略过 ...

  10. HDU_1856_带权并查集

    有10000000个同学,他们之间可能是直接朋友或者间接朋友,问最大的朋友圈有多少人. 一直觉得10000000的数组开不了,用map优化了一下,结果能开,且10000000也不会超时... #inc ...