一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
什么是栈
栈是一种线性的数据结构,它常用来存储一系列同类型的元素。
它和数组或者队列非常相似,区别在于它们的添加删除元素的顺序。对于栈来说,它是后进先出的顺序,即 Last In First Out - LIFO。
对于栈的理解,大家可以想象这样一个场景:你的书桌上摞了一堆书,这堆书最上面的一本,肯定是最后放上去的。而你如果想阅读其中一本的话,你也会从最上面一本一本的往下拿。这种结构,对应的就是栈的结构。
理解了什么是栈,下面来看一下实现栈需要实现那些函数。
需要实现的函数
func isEmpty() -> Bool // 栈是否为空
func count() -> Int // 获取栈里有多少元素
func push(_ newElement: Element) // 入栈
func pop() -> Element? // 出栈
func top() -> Element? // 获取栈顶元素
func removeAll() // 移除栈里所有元素
因为在 Swift 中,Array 其实已经提供了栈的相同作用的函数。所以,这次我们底层使用 Array 来存储数据。
栈的完整实现:
class Stack<Element: Equatable> {
private var _content = [Element]()
func isEmpty() -> Bool {
return _content.isEmpty
}
func count() -> Int {
return _content.count
}
func push(_ newElement: Element) {
_content.append(newElement)
}
func pop() -> Element? {
guard count() > 0 else {
return nil
}
return _content.popLast()
}
func top() -> Element? {
guard count() > 0 else {
return nil
}
return _content.last
}
func removeAll() {
_content.removeAll()
}
}
代码解释:
- isEmpty/count/removeAll 直接调用 Array 的相应函数实现。
- push:在栈顶添加元素,对应的就是 Array 的尾部,所以,调用 append 来添加。
- pop:移除栈顶元素,调用 Array 的 popLast 即移除尾部元素。
- top:获取栈顶元素,Array 的 last 属性即是返回数组的尾部元素。
虽然,Swift 中的 Array 很强大,但自己在用其封装一个栈并不是脱裤子放屁。因为,就笔者而言,如果在刷题的时候,如果直接使用 Array 来代替栈,就经常有一些操作会搞错,因为对于 push、pop 这种操作对应到 popLast 可能会出现偏差。比如:pop 有时一时糊涂就会调用 removeFirst
从而造成一些低级错误。
经典题目
有效的括号
LeetCode 的原题,此处为链接。
这道题就是借助栈的后进先出来解决的:
- 首先用哈希表来存储三种类型的括号:
let dict = ["(":")", "[":"]", "{":"}"]
。 - 遍历当前字符串:
- 如果当前字符为左括号,则入栈。
- 如果当前字符为右括号,则移除栈顶元素。
- 若此时栈为空,则说明当前右括号为多余的,返回 false。
- 判断移除的栈顶元素与当前有括号是否匹配,不匹配直接返回 false。
- 若匹配,则继续遍历。
- 若遍历完字符串: * 栈不为空,则说明有多余的左括号,返回 false。
代码实现:
let dict = ["(":")", "[":"]", "{":"}"]
func isValid(_ s: String) -> Bool {
let stack = Stack<String>()
for char in s {
let subStr = String(char)
if dict.keys.contains(subStr) {
stack.push(subStr)
} else if stack.isEmpty() || dict[stack.pop()!] != subStr {
return false
}
}
return stack.isEmpty()
}