Leetcode 232.用栈实现队列

题目:232.用栈实现队列

初始思路

之前写过用数组实现队列,但是调用了数组的一些API,这里题目要求必须要用两个栈。

代码

  1. var MyQueue = function () {
  2. // 输入和输出栈
  3. this.stackIn = []
  4. this.stackOut = []
  5. };
  6. /**
  7. * @param {number} x
  8. * @return {void}
  9. * 将元素 x 推到队列的末尾
  10. */
  11. MyQueue.prototype.push = function (x) {
  12. this.stackIn.push(x)
  13. };
  14. /**
  15. * @return {number}
  16. * 从队列的开头移除并返回元素
  17. */
  18. MyQueue.prototype.pop = function () {
  19. const size = this.stackOut.length
  20. // 如果输出栈不为空的话,直接弹出即可
  21. if (size) {
  22. return this.stackOut.pop()
  23. }
  24. // 如果输出栈为空的话,要把输出栈的所有元素搬到输出栈中开始弹出
  25. while (this.stackIn.length) {
  26. this.stackOut.push(this.stackIn.pop())
  27. }
  28. return this.stackOut.pop()
  29. };
  30. /**
  31. * @return {number}
  32. * 返回队列开头的元素
  33. */
  34. MyQueue.prototype.peek = function () {
  35. // pop函数返回队列开头的元素
  36. const x = this.pop()
  37. // 改变了队列,再改回去
  38. this.stackOut.push(x)
  39. return x
  40. };
  41. /**
  42. * @return {boolean}
  43. * 如果队列为空,返回 true ;否则,返回 false
  44. */
  45. MyQueue.prototype.empty = function () {
  46. return !this.stackIn.length && !this.stackOut.length
  47. };
  48. /**
  49. * Your MyQueue object will be instantiated and called as such:
  50. * var obj = new MyQueue()
  51. * obj.push(x)
  52. * var param_2 = obj.pop()
  53. * var param_3 = obj.peek()
  54. * var param_4 = obj.empty()
  55. */

感想

  1. 使用输入和输出栈。
  2. 在push数据的时候,只要数据放进输入栈就好
  3. 在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
  4. peek很巧妙,通过pop直接获取队列开头的元素,然后再放回去。
  5. 如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。

Leetcode 225.用队列实现栈

题目:225.用队列实现栈

初始思路

还是用数组,如果是队列的话,那数组只能用push和shift方法,因为只能在队列开头操作

代码

  1. var MyStack = function () {
  2. this.queue = []
  3. };
  4. /**
  5. * @param {number} x
  6. * @return {void}
  7. * 将元素 x 压入栈顶。
  8. */
  9. MyStack.prototype.push = function (x) {
  10. this.queue.push(x)
  11. };
  12. /**
  13. * @return {number}
  14. * 移除并返回栈顶元素。
  15. */
  16. MyStack.prototype.pop = function () {
  17. let size = this.queue.length
  18. while (size-- > 1) {
  19. this.queue.push(this.queue.shift())
  20. }
  21. return this.queue.shift()
  22. };
  23. /**
  24. * @return {number}
  25. * 返回栈顶元素。
  26. */
  27. MyStack.prototype.top = function () {
  28. const x = this.pop()
  29. this.queue.push(x)
  30. return x
  31. };
  32. /**
  33. * @return {boolean}
  34. * 如果栈是空的,返回 true ;否则,返回 false 。
  35. */
  36. MyStack.prototype.empty = function () {
  37. return !this.queue.length
  38. };
  39. /**
  40. * Your MyStack object will be instantiated and called as such:
  41. * var obj = new MyStack()
  42. * obj.push(x)
  43. * var param_2 = obj.pop()
  44. * var param_3 = obj.top()
  45. * var param_4 = obj.empty()
  46. */
  1. var MyStack = function () {
  2. this.queue1 = [];
  3. this.queue2 = [];
  4. };
  5. /**
  6. * Push element x onto stack.
  7. * @param {number} x
  8. * @return {void}
  9. */
  10. MyStack.prototype.push = function (x) {
  11. this.queue1.push(x);
  12. };
  13. /**
  14. * Removes the element on top of the stack and returns that element.
  15. * @return {number}
  16. */
  17. MyStack.prototype.pop = function () {
  18. // 减少两个队列交换的次数, 只有当queue1为空时,交换两个队列
  19. // 也就是当queue1中的元素都弹出完毕的时候
  20. if (!this.queue1.length) {
  21. [this.queue1, this.queue2] = [this.queue2, this.queue1];
  22. }
  23. // 把queue1中除了最后一个元素都放入queue2
  24. while (this.queue1.length > 1) {
  25. this.queue2.push(this.queue1.shift());
  26. }
  27. // 弹出最后面的元素
  28. return this.queue1.shift();
  29. };
  30. /**
  31. * Get the top element.
  32. * @return {number}
  33. */
  34. MyStack.prototype.top = function () {
  35. const x = this.pop();
  36. this.queue1.push(x);
  37. return x;
  38. };
  39. /**
  40. * Returns whether the stack is empty.
  41. * @return {boolean}
  42. */
  43. MyStack.prototype.empty = function () {
  44. return !this.queue1.length && !this.queue2.length;
  45. };

感想

  1. 单队列实现很精妙。在pop方法中,把除了栈顶的元素先弹出在压入,不会改变顺序。
  2. 两个队列实现中,pop方法:把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。

Leetcode 20.有效的括号

题目:20.有效的括号

初始思路

以前在数据结构课上听过,应该是栈的经典应用。在压栈过程中,如果左括号遇到了匹配的右括号就弹栈。

代码

  1. var isValid = function (s) {
  2. let stack = []
  3. for (let i = 0; i < s.length; i++) {
  4. let ch = s[i]
  5. // 如果是左括号就入栈
  6. if (ch === '(' || ch === '[' || ch === '{') {
  7. stack.push(ch)
  8. } else if (ch === ')' || ch === ']' || ch === '}') {
  9. // 如果是右括号就和栈顶元素进行匹配
  10. // 栈顶元素
  11. const p = stack[stack.length - 1]
  12. if ((ch === ')' && p === '(') || (ch === ']' && p === '[') || (ch === '}' && p === '{')) {
  13. // 如果匹配成功就弹出栈顶这个左括号,继续匹配
  14. stack.pop()
  15. } else {
  16. return false
  17. }
  18. }
  19. }
  20. // 当栈内元素都弹出的时候,匹配完成
  21. return stack.length === 0
  22. };
  1. var isValid = function (s) {
  2. const stack = [];
  3. for (let i = 0; i < s.length; i++) {
  4. let c = s[i];
  5. switch (c) {
  6. case '(':
  7. stack.push(')');
  8. break;
  9. case '[':
  10. stack.push(']');
  11. break;
  12. case '{':
  13. stack.push('}');
  14. break;
  15. default:
  16. if (c !== stack.pop()) {
  17. return false;
  18. }
  19. }
  20. }
  21. return stack.length === 0;
  22. };
  23. // 简化版本
  24. var isValid = function(s) {
  25. const stack = [],
  26. map = {
  27. "(":")",
  28. "{":"}",
  29. "[":"]"
  30. };
  31. for(const x of s) {
  32. if(x in map) {
  33. stack.push(x);
  34. continue;
  35. };
  36. if(map[stack.pop()] !== x) return false;
  37. }
  38. return !stack.length;
  39. };

感想

  1. 实现起来其实不困难,挺好写的。但是简单写起来有些繁琐,比起简化版版本来说有些笨拙。

Leetcode 1047.删除字符串中的所有相邻重复项

题目:1047.删除字符串中的所有相邻重复项

初始思路

自己尝试用栈模拟了一下,感觉挺对的。再看一下题解,原来自己模拟的不对,好吧!

代码

  1. var removeDuplicates = function (s) {
  2. let stack = []
  3. for (const ch of s) {
  4. // 栈顶元素
  5. let p = stack[stack.length - 1]
  6. if (stack.length && p === ch) {
  7. // 如果栈不为空并且匹配上了就弹出
  8. stack.pop()
  9. } else {
  10. stack.push(ch)
  11. }
  12. }
  13. return stack.join('')
  14. };
  1. var removeDuplicates = function (s) {
  2. // 解构赋值成数组
  3. s = [...s]
  4. // 指向栈顶元素的下标
  5. let top = -1
  6. for (let i = 0; i < s.length; i++) {
  7. // 栈为空哦或者不匹配
  8. if (top === -1 || s[top] !== s[i]) {
  9. // 入栈
  10. s[++top] = s[i]
  11. } else {
  12. // 出栈
  13. top--
  14. }
  15. }
  16. // 栈顶元素下标 + 1 为栈的长度
  17. s.length = top + 1
  18. return s.join('')
  19. }

感想

  1. 思路挺简单的。
  2. 为什么还能用双指针?