第三章-数据结构之栈

栈-简介

  • 栈是一个后进先出的数据结构。
  • 在 JavaScript 中没有栈这个数据结构,但是可以用 Array 实现栈的所有功能
const stack = [];
stack.push(1); // [1]
stack.push(2); // [1,2]
const item1 = stack.pop(); // item1 = 2 stack = [1]
const item2 = stack.pop(); // item2 = 1 stack = []

栈的应用场景

所有需要 后进先出 的场景都可以考虑使用栈这种数据结构

  1. 十进制转二进制

    • 十进制转二进制中,后出来的余数反而要排到前面
    • 把余数一次入栈,然后再出栈,就可以实现余数的倒序输出
  2. 判断字符串的括号是否有效闭合

    • 越靠后的左括号,对应的右括号越靠前。
    • 左括号入栈,右括号出栈,最后栈空了就是合法的
  3. 函数调用堆栈

    • 最后调用的函数,最先执行完毕
    • JS 解释器使用栈来控制函数的调用顺序

LeetCode 20题:有效的括号

原题链接

【题目描述】给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。

示例:

输入: "()"
输出: true

输入: "()[]{}"
输出: true

输入: "(]"
输出: false

输入: "([)]"
输出: false

输入: "{[]}"
输出: true

【解题思路】

  • 对于没有闭合的左括号而言,越靠后的左括号,对应的右括号越靠前
  • 满足后进先出,考虑使用栈

【解题步骤】

  • 新建一个栈
  • 扫描字符串,遇到左括号入栈,遇到和栈顶括号类型匹配的右括号就出栈,类型不匹配直接判定为不合法
  • 最后栈空了就合法,否则就不合法

【暴力解法】

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    // 如果字符串的长度为奇数就直接判定为 false
    const len = s.length
    if (len % 2 === 1) {
        return false;
    }
	// 新建一个 ‘栈’
    const stack = [];
    for (let i = 0; i < len; i++) {
        const current = s[i];
        const stackTop = stack[stack.length - 1];
        // 如果是左括号就入栈
        if (current === '(' || current === '[' || current === '{') {
            stack.push(current);
        } else {
            // 如果栈顶和第一个右括号类型相同就出栈
            if (
                (stackTop === '(' && current === ')') ||
                (stackTop === '[' && current === ']') ||
                (stackTop === '{' && current === '}')
            ) {
                stack.pop();
            } else {
                // 否则直接返回 false
                return false;
            }
        }
    }
    // 判断栈是否为空
    return stack.length === 0
};

使用map优化

   /**
 * @param {string} s
 * @return {boolean}
 */
  var isValid = function(s) {
    if (s.length % 2 === 1) {
        return false;
    }

    const stack = [];
    let map = new Map();
    map.set('(', ')');
    map.set('[', ']');
    map.set('{', '}');
    for (let i = 0; i < s.length; i++) {
        let stackTop = stack[stack.length - 1];
        if (map.has(s[i])) {
            stack.push(s[i])
        } else {
            // map.get(s[i]) 获取右边括号的第一个值
            if (s[i] === map.get(stackTop)) {
                stack.pop();
            } else {
                return false;
            }
        }
    }
    return stack.length === 0;
  };

LeetCode 144题:二叉树的前序遍历

原题链接

【题目描述】

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

1
 \
  \
   2
  /
 /
3 
输入:root = [1,null,2,3]
输出:[1,2,3]

【解题思路】

利用栈的特性解题

  • 新建一个 res 存放结果,stack 栈作为
  • 前序遍历,左子树先访问,所以先将右子树进栈,再将左子树进栈

【答案】

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    const res = [];
    const stack = [];
    if (root) stack.push(root);
    while(stack.length) {
        let n = stack.pop();
        res.push(n.val);
        if (n.right) stack.push(n.right);
        // 左子树  后进栈,先出栈
        if (n.left) stack.push(n.left);
    }
    return res;
};

思考题

  1. 请用一个 ES6 的 class,封装一个 Stack 类,包括 push、pop、peek 方法。

    class Stack {
      constructor() {
        this.stack = [];
        this.count = 0;
      }
      push (item) {
        this.stack = [...this.stack, item]
        this.count++
        return this.stack
      }
      pop () {
        if (this.count === 0) return undefined;
        let remove = this.stack[this.count - 1];
        delete this.stack[this.count - 1];
        this.count--
        return remove
      }
      peek () {
        if (this.count === 0) return undefined;
        return this.stack[this.count - 1];
      }
    }
    
    // let stack = new Stack()
    // stack.push(1)
    // stack.push(2)
    // stack.push(3)
    // stack.push(4)
    // let res = stack.push(5)
    // console.log(res)
    // // stack.pop()
    // // stack.pop()
    // let res1 = stack.pop()
    // console.log(res1)
    // console.log(stack.peek())
    
  2. 请用栈这个数据结构,将十进制的 100 转为二进制数。

    function toBinary (num) {
      let stack = [];
      let res = [];
      while (num > 0) {
        stack.push(num % 2);//1 1 
        num = Math.floor(num / 2);
      }
      // 在循环的时候,stack 的 length 会改变,
      // 因此要在for循环外部定义 stack 的长度
      let len = stack.length;
      for (let i = 0; i < len; i++) {
        res.push(stack.pop())
      }
      return res.join('');
    }
    
    let res = toBinary(100);
    console.log(res); // 1100100
    
posted @ 2020-11-07 13:46  公瑾当年  阅读(124)  评论(0编辑  收藏  举报