有效的括号——哈希表+栈解法

前言

已经写了几篇关于栈算法的博文,我自己都不由得有点困惑栈这个知识点的纹路是什么应该如何理解,什么样的问题适用于用栈来求解

在查了资料后,在这里与大家浅谈下这些令人困惑,但解释得很明晰的知识点——

如何理解栈

  • 数据结构与算法中,栈是一种满足后进先出特点的数据存放方式,可以认为这里的栈是一种逻辑结构,这种存放方式也配套了压栈,出栈,判空的方法。

  • 我们通常说的,方法的栈帧即是代码的运行方式,当程序运行后,调用一个方法就会为这个方法申请一个栈帧,方法返回后释放这个栈帧即可。

  • 存放数据的内存区域,在内存中,有栈和堆两种内存区域,栈是有结构的,每个区块按照一定的次序存放。heap中的数据可以随意存放。在java中,对象都被存储在heap中,而局部变量放在stack中,方法结束后,stack被清空,而heap的空间则要等到垃圾回收器自动回收,所以内存泄漏通常发生在heap。此外:

    stack内变量的分配速度会比heap快很多,只需要修改sp寄存器,heap内分配需要调用malloc。 stack的寻址也会比heap快,通过sp/fp寄存器间接寻址。

栈可以解决什么问题(来自https://juejin.cn/post/6844904132734615565)

  • 数据是线性
  • 问题中常常涉及到数据的来回比较,匹配问题;例如,每日温度,括号匹配,字符串解码,去掉重复字母等问题.
  • 问题中涉及到数据的转置,例如进制问题.链表倒序打印问题等
  • 利用栈思想解决问题时,首先需要透彻的解析问题之后,找到问题解决的规律.才能使用它解决;思想只有指导作用,遇到不同的题目,需要个例分析.在基本思想上去找到解决问题之道;

1.1 问题描述

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

示例 1

​ 输入:s = “()”
​ 输出:true

1.2 思路及复杂度分析

显然,经过模式识别,这是数据来回比较的问题,所以首先将其归类到使用栈解决,而既然使用栈可以解决,那数组和链表自然也就可以,当然,这是题外话啦。

这里先介绍下我在解决这道题的时候是怎么想的,我并没有考虑到形成固定的模式,即使用集合将匹配的字符对存储下来。而是平铺直叙地遍历字符,再switch case一通搞定,然后我就陷入不停的逻辑追加环节了。自然最后跑出来的复杂度也是相当感人了,但这个过程很重要,不然直接看题解容易一看就会,一写全废~

好啦,那怎么优化呢?显然,我们不希望有不合法的字符混进来,所以会用HashMap保存字符对就势在必行了,另外特判自然是起手式,核心就在于逻辑分支,即包含key的话,就无脑压栈,不包含key的话,分情况讨论,要入栈的元素和栈顶元素对应的value相同的话,弹栈,否则,也就是非法字符的情况,直接一手false.

最后,进入复杂度分析环节——

  • 时间复杂度:遍历元素即是量级最大的代码了,所以时间复杂度为O(n).
  • 空间复杂度:最坏情况下,不停压栈,所以空间复杂度为O(n).

1.3 趣味图解

  • 图片来自:https://leetcode-cn.com/problems/valid-parentheses/solution/zhu-bu-fen-xi-tu-jie-zhan-zhan-shi-zui-biao-zhun-d/

20.gif

1.4 代码演示

/**
*有效地括号
*/
class Solution {
    public boolean isValid(String s) {
    //特判
    //奇数则返回false
    if(s.length()%2 != 0)
        return false;
    //将对应的元素对插入到hashmap中
    HashMap<Character, Character> map = new HashMap<>();
    map.put('{','}');
    map.put('(',')');
    map.put('[',']');
    //声明栈
    Deque<Character> stack = new LinkedList<>();
    //遍历字符串中固定下标的元素
    for(int i=0;i<s.length();i++) {
        char ch = s.charAt(i);
        //如果map中存在这样的key,入栈
        if (map.containsKey(ch)) {
            stack.push(ch);
        } else {//不存在
            if (!stack.isEmpty() && ch==map.get(stack.peek())) {//栈不为空,与栈顶元素比较
                stack.pop();
            }else{
                return false;
            }   
        }
    }
    //返回栈是否为空
    return stack.isEmpty();
    }
}

日拱一卒,功不唐捐。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值