1、有效的括号

给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

解答:利用栈的后进先出的特性,如果是括号的左边则进栈,否则查看栈顶和当前括号字符是否闭合。最后查看栈是否为空,为空则有效,否则无效

  1. /**
  2. * @param {string} s
  3. * @return {boolean}
  4. */
  5. var isValid = function(s) {
  6. const map = new Map([['(', ')'], ['[', ']'], ['{', '}']])
  7. const stack = []
  8. for (let i = 0; i < s.length; i ++) {
  9. const char = s[i]
  10. if (map.has(char)) {
  11. stack.push(char)
  12. } else {
  13. const topChar = stack.pop()
  14. if (map.get(topChar) !== char) return false
  15. }
  16. }
  17. return stack.length === 0
  18. };

2、栈的最小值

请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

解答:难点在于查找min。可以使用两个栈,其中一个栈专门用来保存最小值。利用栈的后进先出的特性可以保证栈顶总是最小值。

  1. /**
  2. * initialize your data structure here.
  3. */
  4. var MinStack = function() {
  5. this.stack = []
  6. this.minStack = []
  7. };
  8. /**
  9. * @param {number} x
  10. * @return {void}
  11. */
  12. MinStack.prototype.push = function(x) {
  13. this.stack.push(x)
  14. if (
  15. this.minStack.length === 0 ||
  16. this.minStack[this.minStack.length - 1] >= x
  17. ) {
  18. this.minStack.push(x)
  19. }
  20. };
  21. /**
  22. * @return {void}
  23. */
  24. MinStack.prototype.pop = function() {
  25. if (this.stack.length === 0) throw new Error()
  26. const top = this.stack.pop()
  27. if (top === this.minStack[this.minStack.length - 1]) this.minStack.pop()
  28. };
  29. /**
  30. * @return {number}
  31. */
  32. MinStack.prototype.top = function() {
  33. return this.stack[this.stack.length - 1]
  34. };
  35. /**
  36. * @return {number}
  37. */
  38. MinStack.prototype.getMin = function() {
  39. if (this.minStack.length === 0) throw new Error()
  40. return this.minStack[this.minStack.length - 1]
  41. };
  42. /**
  43. * Your MinStack object will be instantiated and called as such:
  44. * var obj = new MinStack()
  45. * obj.push(x)
  46. * obj.pop()
  47. * var param_3 = obj.top()
  48. * var param_4 = obj.getMin()
  49. */

3、用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

解答1:难点在于队列是先进先出,而栈是先进后出。也就是说如果要使用队列模拟栈,则队列中元素顺序应该是和栈相反。简单来说,就是每次push的元素需要放在队首,这样每次push操作后,队列的顺序就是和栈相反。为了达到这个目的,可以使用一个辅助队列,一个存放数据的数据队列,每次将新元素push进辅助队列,然后如果数据队列中有元素,则将数据队列中的元素依次出队放入辅助队列。然后交换两个队列。这样每次push结束后辅助队列总是空的,数据队列中则放置所有的数据且顺序和元素push顺序相反。

  1. var MyStack = function() {
  2. this.queue1 = []
  3. this.queue2 = []
  4. };
  5. /**
  6. * @param {number} x
  7. * @return {void}
  8. */
  9. MyStack.prototype.push = function(x) {
  10. this.queue2.push(x)
  11. while (this.queue1.length) {
  12. this.queue2.push(this.queue1.shift())
  13. }
  14. let temp = this.queue1
  15. this.queue1 = this.queue2
  16. this.queue2 = temp
  17. };
  18. /**
  19. * @return {number}
  20. */
  21. MyStack.prototype.pop = function() {
  22. return this.queue1.shift()
  23. };
  24. /**
  25. * @return {number}
  26. */
  27. MyStack.prototype.top = function() {
  28. return this.queue1[0]
  29. };
  30. /**
  31. * @return {boolean}
  32. */
  33. MyStack.prototype.empty = function() {
  34. return this.queue1.length === 0
  35. };
  36. /**
  37. * Your MyStack object will be instantiated and called as such:
  38. * var obj = new MyStack()
  39. * obj.push(x)
  40. * var param_2 = obj.pop()
  41. * var param_3 = obj.top()
  42. * var param_4 = obj.empty()
  43. */

解答2:根据解答1,其实使用一个队列即可完成,具体方法是push操作时每次push新元素到队列中,假设队列长度为n,然后将队列的前n-1个元素依次出队然后再入队即可。

  1. var MyStack = function() {
  2. this.queue = []
  3. };
  4. /**
  5. * @param {number} x
  6. * @return {void}
  7. */
  8. MyStack.prototype.push = function(x) {
  9. this.queue.push(x)
  10. let len = this.queue.length
  11. while (len > 1) {
  12. this.queue.push(this.queue.shift())
  13. len --
  14. }
  15. };
  16. /**
  17. * @return {number}
  18. */
  19. MyStack.prototype.pop = function() {
  20. return this.queue.shift()
  21. };
  22. /**
  23. * @return {number}
  24. */
  25. MyStack.prototype.top = function() {
  26. return this.queue[0]
  27. };
  28. /**
  29. * @return {boolean}
  30. */
  31. MyStack.prototype.empty = function() {
  32. return this.queue.length === 0
  33. };
  34. /**
  35. * Your MyStack object will be instantiated and called as such:
  36. * var obj = new MyStack()
  37. * obj.push(x)
  38. * var param_2 = obj.pop()
  39. * var param_3 = obj.top()
  40. * var param_4 = obj.empty()
  41. */

4、用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)。

解答1:和上题一样,需要改变顺序。利用栈先进后出的特性,将一个栈的元素依次取出放进另一个栈,就完成了顺序的颠倒。因此使用一个辅助栈和一个存放数据的数据栈,数据栈存放最终的数据,辅助栈用于颠倒顺序。每次push操作的时候先将数据栈的元素依次放进辅助栈(还原顺序),然后将新元素推入辅助栈,再将辅助栈的元素推入数据栈。最终得到一个顺序颠倒的数据栈。

  1. var MyQueue = function() {
  2. this.stack1 = []
  3. this.stack2 = []
  4. };
  5. /**
  6. * @param {number} x
  7. * @return {void}
  8. */
  9. MyQueue.prototype.push = function(x) {
  10. while (this.stack1.length) {
  11. this.stack2.push(this.stack1.pop())
  12. }
  13. this.stack2.push(x)
  14. while (this.stack2.length) {
  15. this.stack1.push(this.stack2.pop())
  16. }
  17. };
  18. /**
  19. * @return {number}
  20. */
  21. MyQueue.prototype.pop = function() {
  22. return this.stack1.pop()
  23. };
  24. /**
  25. * @return {number}
  26. */
  27. MyQueue.prototype.peek = function() {
  28. return this.stack1[this.stack1.length - 1]
  29. };
  30. /**
  31. * @return {boolean}
  32. */
  33. MyQueue.prototype.empty = function() {
  34. return this.stack1.length === 0
  35. };
  36. /**
  37. * Your MyQueue object will be instantiated and called as such:
  38. * var obj = new MyQueue()
  39. * obj.push(x)
  40. * var param_2 = obj.pop()
  41. * var param_3 = obj.peek()
  42. * var param_4 = obj.empty()
  43. */

解答2:上述方法逻辑清晰,但是每次push都需要进行两次while循环比较耗费性能。实际从解答1得知,数据栈存放的元素顺序是和队列的顺序相反的,也就是说每次只要数据栈不为空,每次pop的时候从数据栈出栈一个元素即可。如果数据栈为空,再将辅助栈元素全部推进数据栈即可。这里的关键在于将方法一每次push操作进行while循环改成数据栈为空时再进行while循环。

  1. var MyQueue = function() {
  2. this.stack1 = []
  3. this.stack2 = []
  4. this.front = null
  5. };
  6. /**
  7. * @param {number} x
  8. * @return {void}
  9. */
  10. MyQueue.prototype.push = function(x) {
  11. this.stack2.push(x)
  12. if (this.stack2.length === 1) this.front = x // 保存辅助栈的栈底元素,当将辅助栈推送到数据栈时,栈底元素就变成了队首元素,也就是peek的返回值
  13. };
  14. /**
  15. * @return {number}
  16. */
  17. MyQueue.prototype.pop = function() {
  18. if (this.empty()) throw new RangeError('cannot pop element from empty queue.')
  19. if (this.stack1.length === 0) {
  20. while (this.stack2.length) {
  21. this.stack1.push(this.stack2.pop())
  22. }
  23. }
  24. return this.stack1.pop()
  25. };
  26. /**
  27. * @return {number}
  28. */
  29. MyQueue.prototype.peek = function() {
  30. if (this.stack1.length) return this.stack1[this.stack1.length - 1]
  31. return this.front
  32. };
  33. /**
  34. * @return {boolean}
  35. */
  36. MyQueue.prototype.empty = function() {
  37. return this.stack1.length === 0 && this.stack2.length === 0
  38. };
  39. /**
  40. * Your MyQueue object will be instantiated and called as such:
  41. * var obj = new MyQueue()
  42. * obj.push(x)
  43. * var param_2 = obj.pop()
  44. * var param_3 = obj.peek()
  45. * var param_4 = obj.empty()
  46. */