JS算法之栈的压入弹出序列及从上到下打印二叉树

292 阅读3分钟

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

栈的压入、弹出序列

剑指Offer 31.栈的压入、弹出序列

难度:中等

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该压栈序列的弹出序列。

示例1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

  1. 0 <= pushed.length == popped.length <= 1000
  2. 0 <= pushed[i],popped[i] < 1000
  3. pushed是popped的排列

题解

辅助栈

构造一个辅助栈来stack模拟压栈序列pushed的出栈,主要步骤如下:

  1. 入栈:按照压栈序列pushed的顺序入栈。
  2. 出栈:每次出栈后,需要循环判断stack的栈顶是否等于弹出序列popped的当前元素,将符合弹出序列顺序popped的栈顶全部弹出。
/**
 * @param {number[]} pushed
 * @param {number[]} popped
 * @return {boolean}
 */
var validateStackSequences = function(pushed,popped){
  // 辅助栈
  const stack = [];
  // 指向popped当前的下标
  let index = 0; 
  // 把pushed的元素一个个入栈
  for(let i = 0,len = pushed.length - 1;i <= len;i++){
    stack.push(pushed[i]);
    // 把入栈的当前元素和popped当前指向的元素进行对比
    // 相等的话就把辅助栈出栈
    // popped下标往右移动
    while(stack.length > 0 && stack[stack.length - 1] === popped[index]){
      stack.pop();
      index++;
    }
  }
  return !stack.length;
}

从上到下打印二叉树

剑指Offer 32 - I.从上到下打印二叉树

难度:中等

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:给定二叉树:[3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回:

[3,9,20,15,7]

提示:节点总数 <= 1000

题解

层序遍历

使用一个队列来存储有用的节点。步骤如下:

  • 将root放入队列
  • 取出队首元素,将val放入返回的数组中
  • 取出队首元素的子节点,若不为空,则将子节点放入队列
  • 检查队列是否为空,为空则返回数组;否则,回到第二步

JS中的队列都是使用数组来实现:

  • 入队:queue.push(val)
  • 出队:queue.shift()
  • 检查是否为空:!!queue.length
  • 查看队首元素:queue[0]
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var levelOrder = function(root){
  if(!root){
    return [];
  }
  const data = [];
  const queue = [root]; // 队列
  while(queue.length){
    const head = queue.shift(); // 出队
    data.push(head.val);
    head.left && queue.push(head.left); // 入队
    head.right && queue.push(head.right);// 入队
  }
  return data;
}

时间复杂度O(n)、空间复杂度O(n)

从上到下打印二叉树 ||

剑指Offer 32 - II.从上到下打印二叉树 II

难度:中等

从上到下按层打印二叉树,同一层的节点按照从左到右的顺序打印,每一层打印到一行。

例如:给定二叉树:[3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回:

[
  [3],
  [9,20],
  [15,7]
]

提示:节点总数 <= 1000

题解

层序遍历

与上题《剑指Offer 32 - I.从上到下打印二叉树》类似,步骤如下:

  • 将root放入队列
  • 创建data用于存放返回的结果、level代表层树。
  • 检查queue是否为空
    • 不为空,依次遍历当前queue内所有节点,检查每个节点的左右子节点,如果左右子节点不为空,则继续将其放入queue,继续循环
    • 为空,则跳出循环
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
	if(!root) return [];
  const queue = [root];
  const data = []; // 存放遍历结果
  let level = 0; // 代表当前层数
  while(queue.length){
    data[level] = []; // 第level层的遍历结果
    let levelNum = queue.length;// 第level层的节点数量(例子中每层分别的节点数量为1、2、2)
    while(levelNum--){
      const head = queue.shift();
      data[level].push(head.val);
      head.left && queue.push(head.left);
      head.right && queue.push(head.right);
    }
    level++;
  }
  return data;
};

时间复杂度O(N)、空间复杂度O(N)

从上到下打印二叉树 III

剑指Offer 32 - III.从上到下打印二叉树 III

难度:中等

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到后的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:给定二叉树:[3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回:

[
  [3],
  [20,9],
  [15,7]
]

提示:节点总数 <= 1000

题解

层序遍历

与上题《剑指Offer 32 - II.从上到下打印二叉树 II》类似,步骤如下:

  • 将root放入队列
  • 创建data用于存放返回的结果、level代表层树。
  • 检查queue是否为空
    • 不为空,依次遍历当前queue内所有节点,检查每个节点的左右子节点,如果左右子节点不为空,则继续将其放入queue,继续循环;再其后面加上判断层数是否为偶数,为偶数则将那一层的结果做倒序处理。
    • 为空,则跳出循环
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
	if(!root) return [];
  const queue = [root];
  const data = []; // 存放遍历结果
  let level = 0; // 代表当前层数
  while(queue.length){
    data[level] = []; // 第level层的遍历结果
    let levelNum = queue.length;// 第level层的节点数量(例子中每层分别的节点数量为1、2、2)
    while(levelNum--){
      const head = queue.shift();
      data[level].push(head.val);
      head.left && queue.push(head.left);
      head.right && queue.push(head.right);
    }
    if(level % 2===1){ // level是从0开始的,所以level为1时,对应的是第二层
      data[level].reverse();
    }
    level++;
  }
  return data;
};

时间复杂度O(N)、空间复杂度O(N)


坚持每日一练!前端小萌新一枚,希望能点个哇~