面试高频:栈--3题多动图1模板把栈讲明白

猿六今天复习完栈的相关知识,打算玩会游戏放松一下,突然接到面试官的电话,急忙跑到厕所接听。

面试官:猿同学,你简历上说熟悉数据结构,说说你对栈的理解。
猿六:先进后出,后进先出,就像羽毛球桶一样,桶口的羽毛球先被用,里面的羽毛球后被用。
在这里插入图片描述
面试官:你来用数组实现下栈,功能有:进栈,出栈,求栈顶元素,判断栈是否为空。
面试官:假设最多做10W次进栈出栈操作,所有操作合法。
猿六:具体过程如下:

  1. 初始化:数组stk保存元素,从stk[1]开始存储。top指向栈顶元素,栈为空的时候,top = 0.
  2. 判断栈是否为空:top等于0栈空,top 大于 0 栈非空。
  3. 入栈:top 增大 1,stk[top] 中放入入栈元素。
  4. 出栈:top 减小1。
  5. 求栈顶元素:返回stk[top]

代码如下:

private:int stk[100010];int top = 0;
public:void push(int x)//top+1后放入x{
​        stk[++top] = x;}int quary()//返回top处存储的值:stk[top]{return stk[top];}void pop()//top--即可{
​        top--;}bool isEmpty()//空返货0,非空返回1{return top == 0 ? 0 : 1;}
};

面试官:说几个算法中用的栈的情况。
猿六:直接用到栈性质的有括号匹配问题。

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true

算法原理:

是否是有效括号不能通过计算左右括号的数量进行判断。

假如输入: [{]},每种括号的左右数量分别相等,但不是有效的括号。因此有效括号不仅要求每种括号的左右数量相同,还与括号位置有关。

可以这样做:对给定的字符串 s 进行遍历,当遇到一个左括号时,希望在后续的遍历中,有一个相同类型的右括号与其配对。由于后遇到的左括号要先闭合,符合后进先出的原则,可以用栈来进行处理。

当遇到一个右括号时,需要一个相同类型的左括号闭合。取出栈顶的左括号,判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,则字符串 s 无效,返回 false。如果遍历完字符串s后,栈为空,则字符串 s 合法,返回 true。

以:“({}[])” 为例,过程如下:
在这里插入图片描述
代码如下:

class Solution {
public:
    bool Ismatch(const char& rhs,const char& lhs)//判断是否匹配
    {
        switch(lhs)
        {
            case '(':
            return rhs==')';
            case '[':
            return rhs==']';
            case '{':
            return rhs=='}';
            default:
            return false;
        }
    }
    bool isValid(string s) {
        if(s.size() % 2 != 0) return 0; //字符串长度不是偶数,不合法
        char stk[100010];
        int top = 0;
        for(auto c : s)
        {
            if(c == '(' || c == '[' || c == '{')//做符号进栈
                stk[++top] = c;
            else if(top && Ismatch(c, stk[top]))//右符号与栈顶匹配,栈顶出栈
                top--;
            else 
                return false;
        }
        if(!top)//栈空,字符串合法
            return true;
        return false;
    }
};

面试官:单调栈你了解吗,讲讲对单调栈的理解和具体使用场景。
猿六:单调栈的性质如下:

  1. 单调栈里面的元素具有单调性;
  2. 元素加入栈前会把栈顶破坏单调性的元素删除;
  3. 使用单调栈可以找到元素向左遍历的第一个比他小的元素(单增栈),也可以找到元素向左遍历第一个比他大的元素(单减栈);

一般使用单调栈的题目具有以下的两点:

  • 离自己最近(栈的后进先出的性质)
  • 比自己大(小)、高(低);

模拟一下单调递增栈:
有一个组数3,10,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值大于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素大的元素全部出栈后,元素再入栈。

  • 3入栈时,栈为空,直接入栈,栈内元素为3。 10入栈时,栈顶元素3比10小,入栈,栈内元素为 3,10。
  • 7入栈时,栈顶元素10比7大,栈顶元素出栈,此时栈顶元素为 3,比7小。7入栈,栈内元素为 3,7。
  • 4入栈时,栈顶元素7比4大,则栈顶元素出栈,此时栈顶元素为 3,比4小。4入栈,栈内元素为 3,4。
  • 12入栈时,栈顶元素4比12小,12入栈,栈内元素为 3,4,12。

模板代码:

//cpp
//作者:yxc
stack<int> stk;
for (遍历这个数组)
{
	if (栈空 || 栈顶元素大于等于当前比较元素)
	{
		入栈;
	}
	else
	{
		while (栈不为空 && 栈顶元素小于当前元素)
		{
			栈顶元素出栈;
			更新结果;
		}
	当前数据入栈;
	}
}

面试官:说说具体可以用在什么地方。
猿六:例如这道题,可以用单调栈解决。

给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1。
输入格式
第一行包含整数N,表示数列长度。 第二行包含N个整数,表示整数数列。
输出格式 共一行,包含N个整数,其中第i个数表示第i个数的左边第一个比它小的数,如果不存在则输出-1。

算法原理:
用单调递增栈,当该元素可以入栈的时候,栈顶元素就是它左侧第一个比它小的元素。
以:3 4 2 7 5 为例,过程如下:
在这里插入图片描述
代码如下:

//cpp
//作者:yxc
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        while (tt && stk[tt] >= x) tt -- ;
        if (!tt) printf("-1 ");
        else printf("%d ", stk[tt]);
        stk[ ++ tt] = x;
    }
    return 0;
}

面试官:再说说栈还能用到什么地方。
猿六 :下面这些问题的题解中,都用到了栈。

Leetcode 42:接雨水
Leetcode 496:下一个更大元素 I
Leetcode 503:下一个更大元素 II
Leetcode 739:每日温度
Leetcode 94. 二叉树的中序遍历
Leetcode144. 二叉树的前序遍历

面试官:恩,今天先到这,等下一轮面试吧。
猿六: 恩恩,谢谢黑脸面试官。
面试官:你说谁脸黑,你没下一次面试了。

我是猿六,喜欢讲故事的程序员
准备了halfrost大神的孔雀书以及经典巨著算法导论。公众号后台点击电子书,直接获取

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值