前言
已经写了几篇关于栈算法的博文,我自己都不由得有点困惑栈这个知识点的纹路是什么
,应该如何理解,什么样的问题适用于用栈来求解。
在查了资料后,在这里与大家浅谈下这些令人困惑,但解释得很明晰
的知识点——
如何理解栈
-
在
数据结构与算法
中,栈是一种满足后进先出特点的数据存放方式,可以认为这里的栈是一种逻辑结构,这种存放方式也配套了压栈,出栈,判空
的方法。 -
我们通常说的,方法的栈帧即是代码的运行方式,当程序运行后,调用一个方法就会为这个方法
申请一个栈帧
,方法返回后释放这个栈帧即可。 -
存放数据的内存区域,在内存中,有栈和堆两种内存区域,
栈是有结构的,每个区块按照一定的次序存放
。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/
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();
}
}
日拱一卒,功不唐捐。