携手创造,共同成长!这是我参加「日新方案 8 月更文应战」的第17天,点击查看活动概况
题目
请你仅运用两个行列完成一个后入先出(LIFO
)的栈,并支撑普通栈的悉数四种操作(push
、top
、pop
和 empty
)。
完成 MyStack
类:
-
void push(int x)
将元素x
压入栈顶。 -
int pop()
移除并回来栈顶元素。 -
int top()
回来栈顶元素。 -
boolean empty()
假如栈是空的,回来true
;否则,回来false
。
留意:
- 你只能运用行列的根本操作 —— 也便是
push to back
、peek
/pop from front
、size
和is empty
这些操作。 - 你所运用的言语也许不支撑行列。 你能够运用
list
(列表)或者deque
(双端行列)来模拟一个行列 , 只要是标准的行列操作即可。
- 输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
- 输出:
[null, null, null, 2, 2, false]
- 解说:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 回来 2
myStack.pop(); // 回来 2
myStack.empty(); // 回来 False
办法一:两个行列
思路及解法
为了满意栈的特性,即最终入栈的元素最先出栈,在运用行列完成栈时,应满意行列前端的元素是最终入栈的元素。能够运用两个行列完成栈的操作,其间 queue1
用于存储栈内的元素,queue2
作为入栈操作的辅佐行列。
入栈操作时,首先将元素入队到 queue2
,然后将 queue1
的悉数元素顺次出队并入队到 queue2
,此刻 queue2
的前端的元素即为新入栈的元素,再将 queue1
和 queue2
交换,则 queue1
的元素即为栈内的元素,queue1
的前端和后端别离对应栈顶和栈底。
因为每次入栈操作都保证 queue1
的前端元素为栈顶元素,因而出栈操作和取得栈顶元素操作都能够简单完成。出栈操作只需求移除 queue1
的前端元素并回来即可,取得栈顶元素操作只需求取得 queue1
的前端元素并回来即可(不移除元素)。
因为 queue1
用于存储栈内的元素,判别栈是否为空时,只需求判别 queue1
是否为空即可。
代码
class MyStack {
var queue1: [Int] = []
var queue2: [Int] = []
init() {
}
func push(_ x: Int) {
queue2.append(x)
while !queue1.isEmpty {
queue2.append(queue1.removeFirst())
}
swap(&queue1, &queue2)
}
func pop() -> Int {
let r: Int = queue1.removeFirst()
return r
}
func top() -> Int {
var r: Int = 0
if !queue1.isEmpty {
r = queue1.first!
}
return r
}
func empty() -> Bool {
return queue1.isEmpty
}
}
复杂度剖析
-
时刻复杂度:入栈操作 O(n)O(n),其余操作都是 O(1)O(1),其间 nn 是栈内的元素个数。
入栈操作需求将 queue1queue1 中的 nn 个元素出队,并入队 n+1n+1 个元素到 queue2queue2,共有 2n+12n+1 次操作,每次出队和入队操作的时刻复杂度都是 O(1)O(1),因而入栈操作的时刻复杂度是 O(n)O(n)。
出栈操作对应将 queue1queue1 的前端元素出队,时刻复杂度是 O(1)O(1)。
取得栈顶元素操作对应取得 queue1queue1 的前端元素,时刻复杂度是 O(1)O(1)。
判别栈是否为空操作只需求判别 queue1queue1 是否为空,时刻复杂度是 O(1)O(1)。 -
空间复杂度:O(n)O(n),其间 nn 是栈内的元素个数。需求运用两个行列存储栈内的元素。
办法二:一个行列
思路及解法
办法一运用了两个行列完成栈的操作,也能够运用一个行列完成栈的操作。
运用一个行列时,为了满意栈的特性,即最终入栈的元素最先出栈,同样需求满意行列前端的元素是最终入栈的元素。
入栈操作时,首先取得入栈前的元素个数 nn,然后将元素入队到行列,再将行列中的前 nn 个元素(即除了新入栈的元素之外的悉数元素)顺次出队并入队到行列,此刻行列的前端的元素即为新入栈的元素,且行列的前端和后端别离对应栈顶和栈底。
因为每次入栈操作都保证行列的前端元素为栈顶元素,因而出栈操作和取得栈顶元素操作都能够简单完成。出栈操作只需求移除行列的前端元素并回来即可,取得栈顶元素操作只需求取得行列的前端元素并回来即可(不移除元素)。
因为行列用于存储栈内的元素,判别栈是否为空时,只需求判别行列是否为空即可。
代码
class MyStack {
var queue: [Int] = []
init() {
}
func push(_ x: Int) {
let n: Int = queue.count
var i: Int = 0
queue.append(x)
while i < n {
i += 1
queue.append(queue.removeFirst())
}
}
func pop() -> Int {
let r: Int = queue.removeFirst()
return r
}
func top() -> Int {
var r: Int = 0
if !queue.isEmpty {
r = queue.first!
}
return r
}
func empty() -> Bool {
return queue.isEmpty
}
}
复杂度剖析
-
时刻复杂度:入栈操作 O(n)O(n),其余操作都是 O(1)O(1),其间 nn 是栈内的元素个数。
入栈操作需求将行列中的 nn 个元素出队,并入队 n+1n+1 个元素到行列,共有 2n+12n+1 次操作,每次出队和入队操作的时刻复杂度都是 O(1)O(1),因而入栈操作的时刻复杂度是 O(n)O(n)。
出栈操作对应将行列的前端元素出队,时刻复杂度是 O(1)O(1)。
取得栈顶元素操作对应取得行列的前端元素,时刻复杂度是 O(1)O(1)。
判别栈是否为空操作只需求判别行列是否为空,时刻复杂度是 O(1)O(1)。 -
空间复杂度:O(n)O(n),其间 nn 是栈内的元素个数。需求运用一个行列存储栈内的元素。