1、有效的括号
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
解答:利用栈的后进先出的特性,如果是括号的左边则进栈,否则查看栈顶和当前括号字符是否闭合。最后查看栈是否为空,为空则有效,否则无效
/*** @param {string} s* @return {boolean}*/var isValid = function(s) {const map = new Map([['(', ')'], ['[', ']'], ['{', '}']])const stack = []for (let i = 0; i < s.length; i ++) {const char = s[i]if (map.has(char)) {stack.push(char)} else {const topChar = stack.pop()if (map.get(topChar) !== char) return false}}return stack.length === 0};
2、栈的最小值
请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。
解答:难点在于查找min。可以使用两个栈,其中一个栈专门用来保存最小值。利用栈的后进先出的特性可以保证栈顶总是最小值。
/*** initialize your data structure here.*/var MinStack = function() {this.stack = []this.minStack = []};/*** @param {number} x* @return {void}*/MinStack.prototype.push = function(x) {this.stack.push(x)if (this.minStack.length === 0 ||this.minStack[this.minStack.length - 1] >= x) {this.minStack.push(x)}};/*** @return {void}*/MinStack.prototype.pop = function() {if (this.stack.length === 0) throw new Error()const top = this.stack.pop()if (top === this.minStack[this.minStack.length - 1]) this.minStack.pop()};/*** @return {number}*/MinStack.prototype.top = function() {return this.stack[this.stack.length - 1]};/*** @return {number}*/MinStack.prototype.getMin = function() {if (this.minStack.length === 0) throw new Error()return this.minStack[this.minStack.length - 1]};/*** Your MinStack object will be instantiated and called as such:* var obj = new MinStack()* obj.push(x)* obj.pop()* var param_3 = obj.top()* var param_4 = obj.getMin()*/
3、用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
解答1:难点在于队列是先进先出,而栈是先进后出。也就是说如果要使用队列模拟栈,则队列中元素顺序应该是和栈相反。简单来说,就是每次push的元素需要放在队首,这样每次push操作后,队列的顺序就是和栈相反。为了达到这个目的,可以使用一个辅助队列,一个存放数据的数据队列,每次将新元素push进辅助队列,然后如果数据队列中有元素,则将数据队列中的元素依次出队放入辅助队列。然后交换两个队列。这样每次push结束后辅助队列总是空的,数据队列中则放置所有的数据且顺序和元素push顺序相反。
var MyStack = function() {this.queue1 = []this.queue2 = []};/*** @param {number} x* @return {void}*/MyStack.prototype.push = function(x) {this.queue2.push(x)while (this.queue1.length) {this.queue2.push(this.queue1.shift())}let temp = this.queue1this.queue1 = this.queue2this.queue2 = temp};/*** @return {number}*/MyStack.prototype.pop = function() {return this.queue1.shift()};/*** @return {number}*/MyStack.prototype.top = function() {return this.queue1[0]};/*** @return {boolean}*/MyStack.prototype.empty = function() {return this.queue1.length === 0};/*** Your MyStack object will be instantiated and called as such:* var obj = new MyStack()* obj.push(x)* var param_2 = obj.pop()* var param_3 = obj.top()* var param_4 = obj.empty()*/
解答2:根据解答1,其实使用一个队列即可完成,具体方法是push操作时每次push新元素到队列中,假设队列长度为n,然后将队列的前n-1个元素依次出队然后再入队即可。
var MyStack = function() {this.queue = []};/*** @param {number} x* @return {void}*/MyStack.prototype.push = function(x) {this.queue.push(x)let len = this.queue.lengthwhile (len > 1) {this.queue.push(this.queue.shift())len --}};/*** @return {number}*/MyStack.prototype.pop = function() {return this.queue.shift()};/*** @return {number}*/MyStack.prototype.top = function() {return this.queue[0]};/*** @return {boolean}*/MyStack.prototype.empty = function() {return this.queue.length === 0};/*** Your MyStack object will be instantiated and called as such:* var obj = new MyStack()* obj.push(x)* var param_2 = obj.pop()* var param_3 = obj.top()* var param_4 = obj.empty()*/
4、用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)。
解答1:和上题一样,需要改变顺序。利用栈先进后出的特性,将一个栈的元素依次取出放进另一个栈,就完成了顺序的颠倒。因此使用一个辅助栈和一个存放数据的数据栈,数据栈存放最终的数据,辅助栈用于颠倒顺序。每次push操作的时候先将数据栈的元素依次放进辅助栈(还原顺序),然后将新元素推入辅助栈,再将辅助栈的元素推入数据栈。最终得到一个顺序颠倒的数据栈。
var MyQueue = function() {this.stack1 = []this.stack2 = []};/*** @param {number} x* @return {void}*/MyQueue.prototype.push = function(x) {while (this.stack1.length) {this.stack2.push(this.stack1.pop())}this.stack2.push(x)while (this.stack2.length) {this.stack1.push(this.stack2.pop())}};/*** @return {number}*/MyQueue.prototype.pop = function() {return this.stack1.pop()};/*** @return {number}*/MyQueue.prototype.peek = function() {return this.stack1[this.stack1.length - 1]};/*** @return {boolean}*/MyQueue.prototype.empty = function() {return this.stack1.length === 0};/*** Your MyQueue object will be instantiated and called as such:* var obj = new MyQueue()* obj.push(x)* var param_2 = obj.pop()* var param_3 = obj.peek()* var param_4 = obj.empty()*/
解答2:上述方法逻辑清晰,但是每次push都需要进行两次while循环比较耗费性能。实际从解答1得知,数据栈存放的元素顺序是和队列的顺序相反的,也就是说每次只要数据栈不为空,每次pop的时候从数据栈出栈一个元素即可。如果数据栈为空,再将辅助栈元素全部推进数据栈即可。这里的关键在于将方法一每次push操作进行while循环改成数据栈为空时再进行while循环。
var MyQueue = function() {this.stack1 = []this.stack2 = []this.front = null};/*** @param {number} x* @return {void}*/MyQueue.prototype.push = function(x) {this.stack2.push(x)if (this.stack2.length === 1) this.front = x // 保存辅助栈的栈底元素,当将辅助栈推送到数据栈时,栈底元素就变成了队首元素,也就是peek的返回值};/*** @return {number}*/MyQueue.prototype.pop = function() {if (this.empty()) throw new RangeError('cannot pop element from empty queue.')if (this.stack1.length === 0) {while (this.stack2.length) {this.stack1.push(this.stack2.pop())}}return this.stack1.pop()};/*** @return {number}*/MyQueue.prototype.peek = function() {if (this.stack1.length) return this.stack1[this.stack1.length - 1]return this.front};/*** @return {boolean}*/MyQueue.prototype.empty = function() {return this.stack1.length === 0 && this.stack2.length === 0};/*** Your MyQueue object will be instantiated and called as such:* var obj = new MyQueue()* obj.push(x)* var param_2 = obj.pop()* var param_3 = obj.peek()* var param_4 = obj.empty()*/
