LeetCode精选题解(Go)之栈和队列

155.最小栈

题目

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) -- 将元素 x 推入栈中。
pop() -- 删除栈顶的元素。
top() -- 获取栈顶元素。
getMin() -- 检索栈中的最小元素。
示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

最小栈对比常规栈多个getMin方法返回栈的最小元素,
要达到常数时间内返回最小值,以空间换时间方法, 得到常数阶的方法。
如果使用单个栈则出栈入栈需要判断最小值,使用两个栈就少去出栈判断最小值的操作。
以下代码使用单个栈操作, 读者可自行使用两个栈进行操作。

代码

// 切片最后一个元素当栈顶
type MinStack struct {
    Elems []int
    Min int // 存储最小值, 如果该处也用栈实现,如果小的元素添加到头部,大的元素添加到尾部,出栈免去最小值查找操作
}


/** initialize your data structure here. */
func Constructor() MinStack {
    // 初始化最小值为有符号int32最大值
    return MinStack{make([]int, 0), 2<<31 - 1}
}


// 入栈
func (this *MinStack) Push(x int)  {
    this.Elems = append(this.Elems, x)
    if x < this.Min {
        this.Min = x
    }
}


// 出栈
func (this *MinStack) Pop()  {
    elem := this.Top()
    this.Elems = this.Elems[:len(this.Elems) - 1]
    if elem <= this.GetMin() {
        min := 2<<31 -1
        for i := 0; i < len(this.Elems); i++ {
            if this.Elems[i] < min{
                min = this.Elems[i]
            }
        }
        this.Min = min
    }
}


// 获取栈顶元素
func (this *MinStack) Top() int {
    if len(this.Elems) == 0 {
        panic("empty stack!")
    }
    elem := this.Elems[len(this.Elems) - 1]
    return elem
}

// 获取最小值
func (this *MinStack) GetMin() int {
    return this.Min
}

232. 用栈实现队列

题目

使用栈实现队列的下列操作:

push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false
说明:

你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-queue-using-stacks
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

入队时候将元素压入栈1, 出队时候将栈1的元素压入栈2,完成数据翻转,此时栈2的栈顶就是需要出队的元素, 栈使用go的切片模拟。

代码

type MyQueue struct {
    In []int
    Out []int
}


/** Initialize your data structure here. */
func Constructor() MyQueue {
    return MyQueue{[]int{}, []int{}}
}


/** Push element x to the back of queue. */
func (this *MyQueue) Push(x int)  {
    this.In = append(this.In, x)
}


/** Removes the element from in front of queue and returns that element. */
func (this *MyQueue) Pop() int {
    this.in2out()
    t := this.Out[len(this.Out) - 1]
    this.Out = this.Out[:len(this.Out) - 1]
    return t
}


/** Get the front element. */
func (this *MyQueue) Peek() int {
    this.in2out()
    return this.Out[len(this.Out) - 1]
}


/** Returns whether the queue is empty. */
func (this *MyQueue) Empty() bool {
    return len(this.In) == 0 && len(this.Out) == 0
}


// 入栈压到出栈中
func (this *MyQueue)in2out()  {
    if len(this.Out) == 0 {
        for len(this.In) > 0 {
            // 出栈
            t := this.In[len(this.In) - 1]
            this.In = this.In[:len(this.In) - 1]
            // 入栈
            this.Out = append(this.Out, t)
        }
    }
}

225.用队列实现栈

题目

使用队列实现栈的下列操作:

push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
注意:

你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-stack-using-queues
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

在队列尾部插入数据x,然后将队列中的元素除了x外进行出队操作,然后再进行一次入队操作即可。

代码

type MyStack struct {
    Queue []int
}


/** Initialize your data structure here. */
func Constructor() MyStack {
    return MyStack{[]int{}}
}


/** Push element x onto stack. */
func (this *MyStack) Push(x int)  {
    this.Queue = append(this.Queue, x)
    cnt := len(this.Queue)
    for cnt > 1 {
        // 移除队头元素
        head := this.Queue[0]
        this.Queue = this.Queue[1:]

        // 插入到队尾
        this.Queue = append(this.Queue, head)
        cnt--
    }
}


/** Removes the element on top of the stack and returns that element. */
func (this *MyStack) Pop() int {
    t := this.Queue[0]
    this.Queue = this.Queue[1:]
    return t
}


/** Get the top element. */
func (this *MyStack) Top() int {
    return this.Queue[0]
}


/** Returns whether the stack is empty. */
func (this *MyStack) Empty() bool {
    return len(this.Queue) == 0
}

20.有效的括号

题目

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true
示例 2:

输入: "()[]{}"
输出: true
示例 3:

输入: "(]"
输出: false
示例 4:

输入: "([)]"
输出: false
示例 5:

输入: "{[]}"
输出: true

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

  • 右括号总是与最近的左括号匹配

  • 从左往右遍历字符串,遇到左括号就入栈,然后遇到右括号时就把它与栈顶出元素对应的左括号匹配

  • 当栈为空时遇到右括号则此右括号无匹配的左括号

  • 当最终右括号匹配完毕后栈内还有剩余元素则表明这些位置的左括号没有与之匹配的右括号

代码

func isValid(s string) bool {
    stack := []int32{}

    for _, c := range s {
        if c == '(' || c == '[' || c == '{' {
            stack = append(stack, c)
        }else { // 遇到非左括号,栈为空则无法完成匹配
            if len(stack) == 0 {
                return false
            }
            // 取栈顶元素
            cStack := stack[len(stack) - 1]
            stack = stack[:len(stack) - 1]
            
            // 判断左右括号是否匹配
            b1 := c == ')' && cStack != '('
            b2 := c == ']' && cStack != '['
            b3 := c == '}' && cStack != '{'
            if b1 || b2 || b3 { 
                return false
            }
        }
    }
    return len(stack) == 0  // 栈中元素为空则匹配,否则不匹配
}

739.每日温度(数组中元素与下一个比它大的元素之间的距离)

题目

根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/daily-temperatures
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

用循环从后往前遍历求解也可以通过,但是此题打了栈标签,考虑使用栈来解决。
可以使用递减栈来进行求解, 递减栈从栈顶到栈底的值是从小到大递增的,遇到入栈元素比栈顶元素小,则先将栈顶出栈再进行入栈操作。

代码

// 递减栈求解
func dailyTemperatures(T []int) []int {
    n := len(T)
    res := make([]int, n)
    stack := []int{}

    for curIdx := 0; curIdx < n; curIdx++ {
        
        for len(stack) > 0 && T[curIdx] > T[stack[len(stack)-1]] { // 取当前元素和栈顶元素进行比较,如果当前元素大于栈顶元素则找到一个元素的值。
            preIdx := stack[len(stack) - 1]
            stack = stack[:len(stack) - 1]
            res[preIdx] = curIdx - preIdx
        }
        stack = append(stack, curIdx)
    }
    return res
}



503.下一更大元素II

题目

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

非严格单调递减栈进行处理, 循环数组将数组长度n扩大两倍,使用i%n进行取元素。
如果栈为空则push进元素,不为空则看元素和栈末尾的元素哪个大,如果元素比栈末尾的元素小则push进栈,否则只要栈末尾的元素比元素下就一直pop出来并设置pop出来的元素的第一个更大的元素就是被比较的元素即可。

代码

func nextGreaterElements(nums []int) []int {
    n := len(nums)
    // 保存结果,默认值设为-1
    next := make([]int, n)
    for i := 0; i < n; i++ {
        next[i] = -1
    }
    stack := []int{}

    for i := 0; i < n * 2; i++ {
        num := nums[i % n] // 取当前元素
        // 栈不为空且栈顶元素小于当前元素
        for len(stack) > 0 && nums[stack[len(stack)-1]] < num {
            
            //将栈顶元素出栈
            pNum := stack[len(stack) - 1]
            stack = stack[:len(stack) - 1]
            // 保存结果
            next[pNum] = num
        }
        if i < n {
            stack = append(stack, i)
        }
    }
    return next
}

你可能感兴趣的:(go,LeetCode精选题解)