0
点赞
收藏
分享

微信扫一扫

Leetcode-栈相关

code_balance 2022-02-04 阅读 37
leetcode

文章目录


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)
}

举报

相关推荐

Leetcode-堆相关

leetcode-回溯

Leetcode-递归

LeetCode-链表

leetcode-数组

LeetCode-树专题

LeetCode-双指针

Leetcode-动态规划

0 条评论