这是我参与更文挑战的第 10 天,活动详情查看: 更文挑战
栈
用数组实现的栈,叫做顺序栈,用链表实现的栈,叫做链式栈。不管是顺序栈还是链式栈,我们存储数据只需要一个大小为 n 的数组就够了。在入栈和出栈的过程中,只需要一两个临时变量存储空间,所以空间复杂度是 O(1)。注意存储数据需要一个大小为 n 的数组,并不是说空间复杂度就是 O(n),因为这 n 个空间是必须的,无法省的。所以我们说空间复杂度的时候,是除了原本的数据存储空间外,算法运行还需要额外的存储空间。
不管是顺序栈还是链式栈,入栈,出栈只涉及栈顶个别数据的操作,所以时间复杂度都是 O(1)
编译器通过两个栈实现表达式求值 如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。
栈在括号匹配中的应用
leetcode上关于栈的题目 20,155,232,844,224,682,496.
递归
递归需要满足的三个条件
- 一个问题的解可以分解为几个子问题的解
- 这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样
- 存在终止递归条件
写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后再推敲代码终止条件,最后将递推公司和终止条件翻译成代码。
编写递归代码的关键是,只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。
递归代码要警惕堆栈溢出,限制递归的做法值适合规模比较小的情况,如果规模大了,可以自己模拟一个栈用非递归代码实现。
递归代码要警惕重复计算
在空间复杂度上,因为递归调用一次就会在内存栈中保存一次现场数据,所以在分析递归代码空间复杂度时,需要额外考虑这部分的开销。
任何递归代码从逻辑上讲都是可以改成迭代循环的非递归写法。