文章目录
q20 有效的括号
有效的括号
题解
遍历字符串,使用栈来保存左括号,遇到右括号时,与栈顶元素作比较即可。
func isValid(s string) bool {
var stack []byte
for i := 0; i < len(s); i++ {
if s[i] == '(' || s[i] == '[' || s[i] == '{' {
stack = append(stack, s[i])
}
if len(stack) == 0 {
return false
}
if s[i] == ')' {
if stack[len(stack) - 1] == '(' {
stack = stack[:len(stack) - 1]
} else {
return false
}
}
if s[i] == ']' {
if stack[len(stack) - 1] == '[' {
stack = stack[:len(stack) - 1]
} else {
return false
}
}
if s[i] == '}' {
if stack[len(stack) - 1] == '{' {
stack = stack[:len(stack) - 1]
} else {
return false
}
}
}
if len(stack) != 0 {
return false
}
return true
}
q32 最长有效括号
题目传送门
题解
这道题可以用栈来解决,采用以下策略:
1.栈内存放括号的位置
2.栈基存放的是最后一个多余右括号的位置,方便计数,初始时压入-1
3.遇到右括号时必须先弹出一个值,然后判断:
- 如果弹出后栈内元素为空,那么更新最后一个多余右括号的位置
- 如果不为空,那就更新最长有效括号的长度,方法是当前下标减去栈顶元素的下标
func longestValidParentheses(s string) int {
maxLength := 0
stack := []int{-1}
for i := 0; i < len(s); i++ {
// 如果是左括号,直接将位置入栈
if s[i] == '(' {
stack = append(stack, i)
} else {
// 不管怎么样,先弹出一个元素
stack = stack[:len(stack) - 1]
// 弹出的是栈基元素,那么更新最后一个多余右括号的下标
if len(stack) == 0 {
stack = append(stack, i)
// 弹出的不是栈基,更新最大值
} else {
if maxLength < i - stack[len(stack) - 1] {
maxLength = i - stack[len(stack) - 1]
}
}
}
}
return maxLength
}
q155 最小栈
题目传送门
题解
这道题的要求是要以常数时间复杂度来找最小值,我使用一个辅助栈来解决。
MinStack结构体中有两个栈,一个主栈,用来存放元素,一个辅助栈,用来存放最小值,辅助栈的栈顶用来储存当前的最小值。
其中辅助栈每次压栈的是当前主栈和新压入元素之间的最小值。这样就可以保证,如果主栈的最小值在栈顶,弹栈后,辅助栈也相应弹栈,这时候辅助栈的栈顶仍然是当前所有元素的最小值。
如图所示:
type MinStack struct {
stack []int
minStack []int
}
func Constructor() MinStack {
return MinStack{
stack: make([]int, 0),
minStack: []int{math.MaxInt32},
}
}
func (this *MinStack) Push(val int) {
this.stack = append(this.stack, val)
if val < this.minStack[len(this.minStack) - 1] {
this.minStack = append(this.minStack, val)
} else {
this.minStack = append(this.minStack, this.minStack[len(this.minStack) - 1])
}
}
func (this *MinStack) Pop() {
this.stack = this.stack[:len(this.stack) - 1]
this.minStack = this.minStack[:len(this.minStack) - 1]
}
func (this *MinStack) Top() int {
return this.stack[len(this.stack) - 1]
}
func (this *MinStack) GetMin() int {
return this.minStack[len(this.minStack) - 1]
}
q224 基本计算器
基本计算器
题解
这道题只有加法和减法,只需要定义一个栈即可。res用于保存最终结果,sign用来标记上一次出现的符号,num用来储存数字。
然后遍历字符串即可,如果是数字就储存在num中,如果是+号或者-号就先累加前面的数字:res += num * sign,接着将sign置为1或者-1,然后num置为0 即可。如果是左括号,那就先将计算结果和括号前的符号压入栈中,然后将res置为0,用于保存括号中的运算结果。当出现右括号时,就将栈中保存的结果与括号里面的计算结果res进行整合。
func calculate(s string) int {
stack, res, num, sign := []int{}, 0, 0, 1
for i := 0; i < len(stack); i++ {
if s[i] >= '0' && s[i] <= '9' {
num = num * 10 + int(s[i] - '0')
} else if s[i] == '+' {
res += sign * num
num = 0
sign = 1
} else if s[i] == '-' {
res += sign * num
num = 0
sign = -1
} else if s[i] == '(' {
// 将前一个结果和符号压入栈中
stack = append(stack, res)
stack = append(stack, sign)
// 将结果置为0, 只需要在括号内计算新结果即可
res = 0
sign = 1
} else if s[i] == ')' {
res += sign * num
num = 0
res *= stack[len(stack) - 1]
res += stack[len(stack) - 2]
stack = stack[:len(stack) - 2]
}
}
// 最后不是以右括号结尾就是以一个数字结尾
if num != 0 {
res += sign * num
}
return res
}
q232 用栈实现队列
题目传送门
题解
题目提供了两个栈,一个作为入队栈stack1,每次入队时压入stack1;一个作为出队栈stack2,每次要出队时,先判断stack2是否为空,如果为空,就将stack1中的所有元素都压入stack2中,然后弹出栈顶元素;如果不为空,直接弹出栈顶元素即可。刚刚好可以实现队列先入先出的特性。
返回队头元素同理。
如果两个栈同时为空,那么队列就为空。
type MyQueue struct {
stack1, stack2 []int
}
func Constructor() MyQueue {
return MyQueue{}
}
func (this *MyQueue) Push(x int) {
this.stack1 = append(this.stack1, x)
}
func (this *MyQueue) Pop() int {
if len(this.stack2) == 0 {
for len(this.stack1) != 0 {
this.stack2 = append(this.stack2, this.stack1[len(this.stack1) - 1])
this.stack1 = this.stack1[:len(this.stack1) - 1]
}
}
front := this.stack2[len(this.stack2) - 1]
this.stack2 = this.stack2[:len(this.stack2) - 1]
return front
}
func (this *MyQueue) Peek() int {
if len(this.stack2) == 0 {
for len(this.stack1) != 0 {
this.stack2 = append(this.stack2, this.stack1[len(this.stack1) - 1])
this.stack1 = this.stack1[:len(this.stack1) - 1]
}
}
front := this.stack2[len(this.stack2) - 1]
return front
}
func (this *MyQueue) Empty() bool {
if len(this.stack1) == 0 && len(this.stack2) == 0 {
return true
} else {
return false
}
}
q316 去除重复字母
题目传送门
题解
首先遍历字符串,记录每个字母出现的次数。然后再次遍历字符串,exist数组用来标记栈中是否已经存在当前字母,如果存在,就跳过。如果不存在则循环与栈顶字母作比较,如果栈顶字母大于当前字母同时后面还存在栈顶元素,就弹出栈顶元素。最后将字母入栈。
func removeDuplicateLetters(s string) string {
var count [26]int
var exist [26]bool
var stack []rune
for _, v := range s {
count[v - 'a']++
}
for _, v := range s {
if exist[v - 'a'] {
count[v - 'a']--
continue
}
// 达到条件应该出栈
// 1.栈里有元素
// 2.栈顶元素大于当前元素
// 3.栈顶元素在后续出现过
for len(stack) > 0 && stack[len(stack) - 1] > v && count[stack[len(stack) - 1] - 'a'] > 0 {
exist[stack[len(stack) - 1] - 'a'] = false
stack = stack[:len(stack) - 1]
}
stack = append(stack, v)
count[v - 'a']--
exist[v - 'a'] = true
}
return string(stack)
}