用两个栈实现队列

来源:牛客网 JZ5

描述

用两个栈来实现一个队列,分别完成在队列尾部插入整数(push)和在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

示例1

1
2
输入:["PSH1","PSH2","POP","POP"]
返回值:1,2

思路

所有元素进stack1,然后全部出stack1并进入stack2.实现队列的先进先出即:若stack2非空,我们需要的恰好再栈顶,出栈;

若要给队列添加元素,即先进sack1,要出队时,若stack2不为空就出栈,为空时就把stack1全部进栈到stack2;

若用两个栈实现一个队列, 思路一般如下:

ps: my ugly code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
	"container/list"
	"fmt"
)

/*
	两个栈实现一个队列
*/
var list1 = list.New()
var list2 = list.New()

//入队 123
func Push(node int) {
	//入栈 123
	list1.PushFront(node)
}

//队先进先出 123
func Pop() int {
	if list2.Len() == 0 {
		for list1.Len() != 0 {
			//栈先进后出 321
			front := list1.Front()
			//入栈 321
			list2.PushFront(list1.Remove(front).(int))
		}

	}

	if list2.Len() > 0 {
		//栈先进后出 123
		first := list2.Front()
		return list2.Remove(first).(int)
	}
	return -1
}

​ 自己本地去构建测试的case, 对正确性做一个验证:

1
2
3
4
5
6
7
func main() {
	Push(1)
	Push(2)
	// Push(3)
	fmt.Println(Pop())
	fmt.Println(Pop())
}

时间复杂度:O(n) 空间复杂度:O(n),需要使用两个栈存储已有的元素。

借助了Golang的库函数, 实现起来比较方便;

测试用例

  • 往空的队列里面添加,删除元素;
  • 往非空的队列里面添加,删除元素;
  • 连续删除元素直至队列为空;

本题考点

  • 考察对栈和队列的理解;
  • 考察分析较为复杂问题的能力;本题最好是能通过手动画图来把抽象的问题具体化,从而解决这个比较复杂的问题;

高手解法与赏析

思路:

push操作就直接往stack1中push, pop操作需要分类对待一下:如果stack2为空,就需要把stack1中的数据转移到stack2中,然后再对stack2进行pop、如果stack2不为空,直接pop就OK;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

var stack1 [] int
var stack2 [] int


func Push(node int) {
	stack1 = append(stack1, node)
}

func Pop() int {
	if len(stack2) == 0 {
		for i := len(stack1) - 1; i >= 0; i-- {
			stack2 = append(stack2, stack1[i])
		}
        stack1 = make([]int, 0)
	}
	if len(stack2) > 0 {
		ret := stack2[len(stack2)-1]
		stack2 = stack2[0 : len(stack2)-1]
		return ret
	}
	return -1
}

这是当前排名第一的Golang代码实现, 简洁无废话, 值得学习;