JS算法(二叉树的镜像、对称的二叉树、顺时针打印矩阵、包含min函数的栈)

503 阅读3分钟

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

二叉树的镜像

剑指Offer 27.二叉树的镜像

难度:简单

请完成一个函数,输入一个二叉树,该函数输出它的镜像。

例如输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

镜像输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

示例1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

限制:0 <= 节点个数 <= 1000

题解

递归法

镜像,即从上到下,依次交换每个节点的左右节点。

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var mirrorTree = function(root){
  if(!root) return null;
  // 交换当前节点的左右节点
  const leftNode = root.left; // 声明临时变量存储左节点
  root.left = root.right;
  root.right = leftNode;
  
  // 对左右子树做相同操作
  mirrorTree(root.left);
  mirrorTree(root.right);
  return root;
}

或
/*
* 声明临时变量temp存储root的左子节点left
* 递归右子节点,将返回值赋给root的左子节点
* 递归左子节点,将返回值赋给root的右子节点
*/
var mirrorTree = function(root){
  if(!root) return root;
  var temp = root.left;
  root.left = mirrorTree(root.right);
  root.right = mirrorTree(temp);
  return root;
}

或

var mirrorTree = function(root){
  if(!root) return null;
  [root.left,root.right] = [mirrorTree(root.right),mirrorTree(root.left)];
  return root;
}

或

var mirrorTree = function(root) {
    return root == null ? null : new TreeNode(root.val, mirrorTree(root.right), mirrorTree(root.left));
};

对称的二叉树

剑指Offer 28.对称的二叉树

难度:简单

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它就是对称的。

例如:二叉树[1,2,2,3,4,4,3]是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个[1,2,2,null,3,null,3]则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

示例1:

输入:root = [1,2,2,3,4,4,3]
输出:true

示例2:

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

限制:0 <= 节点个数 <= 1000

题解

DFS

递归检查左右子树,在递归到下一层时,要同时检查左子树的左和右子树的右:check(left.left,right,right) && check(left.right,right.left)

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function(root){
  if(!root) return true;
  var check = function(left,right){
    if(!left && !right) return true; // 左右子树同时为空,则为镜像
    if(!left || !right) return false;// 左右子树有一个为空,则不为镜像
    return left.val === right.val && check(left.left,right.right) && check(left.right,right.left);
  }
  return check(root.left,root.right)
}

顺时针打印矩阵

剑指Offer 29.顺时针打印矩阵

难度:简单

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

示例1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

限制:

  • 0 <= matrix.length <= 100
  • 0 <= matrix[i].length <= 100

题解

顺时针方向像剥洋葱那样将矩阵一层一层剥掉,其中flag用来切换方向。

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function(matrix){
  var res = [];
  var flag = true;
  while(matrix.length){
    // 从左到右
    if(flag){
      // 第一层
      res = res.concat(matrix.shift());
      // ‘现在’的第一层到最后一层的末尾
      for(let i = 0;i < matrix.length;i++){
        matrix[i].length && res.push(matrix[i].pop());
      };
    }else{// 从右到左
      // 最后一层
      res = res.concat(matrix.pop().reverse());
      // '现在'的最后一层到第一层
      for(let i = matrix.length - 1;i > 0;i--){
        matrix[i]/length && res.push(matrix[i].shift());
      }
    }
    flag = !flag;
  }
  return res;
}

包含min函数的栈

剑指Offer 30.包含min函数的栈

难度:简单

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数在栈中,调用min、push及pop的时间复杂度都是O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

提示:各函数的调用总次数不超过20000次

题解

据题意,需要在O(1)时间找到最小值,这意味着我们不能在寻找最小值的时候,再做排序,查找等操作去获取。

法一 辅助栈法

可以采用空间换时间的原则,创建两个栈,一个栈是主栈stack,另一个是辅助栈minStack,用于存放对应主栈不同时期的最小值。

/**
 * 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);
  // 保持主栈和辅助栈同步,在辅助栈中,存放着每一位主栈元素对应的最小值
  this.minStack.push(Math.min(this.minStack[this.minStack.length - 1], x));
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
	this.stack.pop();
  this.minStack.pop();
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
	return this.stack[this.stack.length - 1];
};

/**
 * @return {number}
 */
MinStack.prototype.min = function() {
	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.min()
 */

法二 迭代

其实挺类似辅助栈法的,迭代法是通过在栈里面存储进一个对象「x,min」的方式,在每一次对栈往里存或者弹出都要保持「x,min」同步,每一个对象中都存放着对应的最小值。

var MinStack = function() {
    this.stack = [];
};

MinStack.prototype.push = function(x) {
    this.stack.push({
        x,min: this.stack.length ? Math.min(this.head().min,x) : x
    });
};

MinStack.prototype.pop = function() {
    this.stack.pop();
};

MinStack.prototype.top = function() {
    return this.head().x;
};

MinStack.prototype.min = function() {
    return this.head().min;
};
// 当前栈的最后一项 即栈顶头 head
MinStack.prototype.head = function(){
    return this.stack[this.stack.length - 1];
}


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