剑指Offer - 面试题30:包含min函数的栈

简介: 剑指Offer - 面试题30:包含min函数的栈

题目

实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。

本题在《程序员代码面试指南-左程云》 第一章 栈和队列 中也有


要求

  1. pop、push、getMin操作的时间复杂度都是O(1)
  2. 设计的栈类型可以使用线程的栈结构

分析

双栈法

我们可以用一个stackmin(辅助栈)栈用来存储每次出栈stackdata(数据栈)或者入栈之后栈中的最小值。


1.入栈。将数据与stackmin的栈顶元素对比,若发现,新来的值小于等于栈顶值,就将该数据也放在stackmin中。否则不添加。只放在stackData中。特殊情况当stackmin为空时,直接将数据放入stackmin中。

2.出栈。如果发现将要出栈的值等于stackmin栈顶值,就stackmin连带出栈。

C++

#include<iostream>
#include<stack>
using namespace std;
template <typename T> class MyStack
{
public:
  MyStack();
  ~MyStack();
  void push(T newNum);
  void pop();
  T top();
  T getmin();
private:
  stack<int> stackData;
  stack<int> stackMin;
};
template <typename T> MyStack<T>::MyStack()
{
}
template <typename T> MyStack<T>::~MyStack()
{
}
template <typename T> void MyStack<T>::push(T newNum)
{
  if (stackMin.empty() == true || newNum <= stackMin.top())
  {
    stackMin.push(newNum);
  }
  stackData.push(newNum);
}
template <typename T> void MyStack<T>::pop()
{
  if (stackData.top() == stackMin.top())
  {
    stackMin.pop();
  }
  stackData.pop();
}
template <typename T> T MyStack<T>::top()
{
  return stackData.top();
}
template <typename T> T MyStack<T>::getmin()
{
  return stackMin.top();
}
int main()
{
  MyStack<int> s;
  s.push(3);
  cout << "入栈。栈中有数据3:最小值为:" << s.getmin() << endl;
  s.push(2);
  cout << "入栈。栈中有数据3、2:最小值为:" << s.getmin() << endl;
  s.push(1);
  cout << "入栈。栈中有数据3、2、1:最小值为:" << s.getmin() << endl;
  s.push(5);
  cout << "入栈。栈中有数据3、2、1、5:最小值为:" << s.getmin() << endl;
  s.push(1);
  cout << "入栈。栈中有数据3、2、1、5、1:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2、1、5:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2、1:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3:最小值为:" << s.getmin() << endl;
  return 0;
}

优化辅助栈

假如我们用一个变量min保存最小值,每次入栈进行比较,然后更新。但是有一个缺陷,一旦删除了最小值,就找不到了新的最小值。所以我们在发现新的最小值要入栈时提前将之前的最小值入栈。当我们删除的值和保存的min值相同时。再从栈中取出栈顶元素(我们事先放好之前的最小值)。给到min中。


C++

#include<iostream>
#include<stack>
using namespace std;
template <typename T> class MyStack
{
public:
  MyStack();
  ~MyStack();
  void push(T newNum);
  void pop();
  T top();
  T getmin();
private:
  stack<int> stackData;
  T stackMin;
};
template <typename T> MyStack<T>::MyStack()
{
}
template <typename T> MyStack<T>::~MyStack()
{
}
template <typename T> void MyStack<T>::push(T newNum)
{
  if (stackData.empty() == true || newNum <= stackData.top())
  {
    stackData.push(stackMin); //把之前的最小值提前入栈
    stackMin = newNum;      //更新新的最小值
  }
  stackData.push(newNum);
}
template <typename T> void MyStack<T>::pop()
{
  if (stackData.empty() == true)
  {
    exit(EXIT_FAILURE);
  }
  if (stackData.top() == stackMin)//删除的是当前的最小值
  {
    stackData.pop();
    stackMin = stackData.top(); //把事先存入栈中的最小值给到stackmin
    stackData.pop();      //再把该值删除
  }
  else
  {
    stackData.pop();
  }
}
template <typename T> T MyStack<T>::top()
{
  return stackData.top();
}
template <typename T> T MyStack<T>::getmin()
{
  return stackMin;
}
int main()
{
  MyStack<int> s;
  s.push(3);
  cout << "入栈。栈中有数据3:最小值为:" << s.getmin() << endl;
  s.push(2);
  cout << "入栈。栈中有数据3、2:最小值为:" << s.getmin() << endl;
  s.push(1);
  cout << "入栈。栈中有数据3、2、1:最小值为:" << s.getmin() << endl;
  s.push(5);
  cout << "入栈。栈中有数据3、2、1、5:最小值为:" << s.getmin() << endl;
  s.push(1);
  cout << "入栈。栈中有数据3、2、1、5、1:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2、1、5:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2、1:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3、2:最小值为:" << s.getmin() << endl;
  s.pop();
  cout << "出栈。栈中有数据3:最小值为:" << s.getmin() << endl;
  return 0;
}


本章完!

目录
相关文章
|
1月前
|
SQL Oracle 关系型数据库
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
本文介绍了多种SQL内置函数,包括单行函数、非空判断函数、日期函数和正则表达式相关函数。每种函数都有详细的参数说明和使用示例,帮助读者更好地理解和应用这些函数。文章强调了字符串操作、数值处理、日期计算和正则表达式的使用方法,并提供了丰富的示例代码。作者建议读者通过自测来巩固学习成果。
22 1
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
|
1月前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
83 2
|
2月前
|
存储
经典面试题:写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个 复制 #define MIN(a,b) ((a)<=(b)?(a):(b))
你的宏定义已非常接近标准。以下是改进后的 `MIN` 宏定义,支持多种数据类型并避免副作用:
|
4月前
|
JavaScript
【Vue面试题八】、为什么data属性是一个函数而不是一个对象?
这篇文章解释了为什么在Vue中组件的`data`属性必须是一个函数而不是一个对象。原因在于组件可能会有多个实例,如果`data`是一个对象,那么这些实例将会共享同一个`data`对象,导致数据污染。而当`data`是一个函数时,每次创建组件实例都会返回一个新的`data`对象,从而确保了数据的隔离。文章通过示例和源码分析,展示了Vue初始化`data`的过程和组件选项合并的原理,最终得出结论:根实例的`data`可以是对象或函数,而组件实例的`data`必须为函数。
【Vue面试题八】、为什么data属性是一个函数而不是一个对象?
|
4月前
|
安全 编译器 C++
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
|
4月前
|
安全 Java
虚拟机栈的五道面试题
这篇文章提供了关于Java虚拟机栈的五个面试问题,涉及栈溢出的情况、栈大小调整、栈内存的分配、垃圾回收与虚拟机栈的关系以及局部变量的线程安全性。
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
1月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
57 4
下一篇
DataWorks