leetcode面试题之二叉树

p101 对称二叉树

/**
 * 101. 对称二叉树
 * 给你一个二叉树的根节点 root , 检查它是否轴对称。
 * https://leetcode-cn.com/problems/symmetric-tree/
 */
/**
 * 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 {boolean}
 * 递归
 */
var isSymmetric = function (root) {
    if (root === null) {
        return true;
    }
    return dfs(root.left, root.right);
};

function dfs(left, right) {
    if (left === null && right === null) {
        return true;
    }
    if (left === null || right === null) {
        return false;
    }
    //注意:此处需要用 !==
    if (left.val !== right.val) {
        return false;
    }
    return dfs(left.left, right.right) && dfs(left.right, right.left);
}


/**
 * @param {TreeNode} root
 * @return {boolean}
 * 队列
 */
var isSymmetric2 = function (root) {
    if (root === null) {
        return true;
    }
    let queue = [];
    queue.push(root);
    while (queue.length > 0) {
        let n = queue.length;
        for (let i = 0; i < n; i ++) {
            let node = queue.shift();
            if (node.left === null && node.right)
            if (node.left && node.right) {

            }
        }
    }
    return dfs(root.left, root.right);
};

p102 二叉树层次遍历

/**
 * 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 levelOrder = function (root) {
    let res = [], queue = [];
    queue.push(root);
    if (root === null) {
        return res;
    }

    //遍历队列,每次遍历都是一层,该层遍历完之后加入res
    while (queue.length !== 0) {
        var length = queue.length;
        //存放每一层的节点
        let level = [];
        for (let i = 0; i < length; i++) {
            //遍历当前节点,将val保存到level
            let node = queue.shift();
            level.push(node.val);
            //存放当前层下一层的节点
            node.left && queue.push(node.left);
            node.right && queue.push(node.right);
        }
        //当层遍历完成,结果放入数组
        res.push(level);
    }
    return res;
};

function TreeNode(val, left, right) {
    this.val = (val === undefined ? 0 : val)
    this.left = (left === undefined ? null : left)
    this.right = (right === undefined ? null : right)
}

p103 之字形层次遍历

设一个flag,偶数反转

/**
 * 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 zigzagLevelOrder = function(root) {
    let res = [], queue = [];
    queue.push(root);
    if (root === null) {
        return res;
    }

    let flag = 0;
    while (queue.length > 0) {
        let n = queue.length;
        let level = [];
        flag++;
        for (let i = 0; i < n; i++) {
            let node = queue.shift();
            level.push(node.val);

            node.left && queue.push(node.left);
            node.right && queue.push(node.right);
        }
        //flag记录遍历层次,偶数层level值反转
        if (flag % 2 === 0) {
            level.reverse();
        }
        res.push(level);
    }
    return res;
};

p104 二叉树的最大深度

/**
 * 104. 二叉树的最大深度
 * 给定一个二叉树,找出其最大深度。
 * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
 * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
 */
/**
 * 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 maxDepth = function(root) {
    let queue = [], count = 0;
    if (root === null) {
        return 0;
    }
    queue.push(root);
    while (queue.length > 0) {
        let n = queue.length;
        count ++;
        for (let i = 0; i < n; i ++) {
            let node = queue.shift();
            node.left && queue.push(node.left);
            node.right && queue.push(node.right);
        }
    }
    return count;
};

p105 从前序与中序遍历构造二叉树

在这里插入图片描述

/**
 * 105. 从前序与中序遍历序列构造二叉树
 * 给定两个整数数组preorder 和 inorder,其中preorder 是二叉树的先序遍历,
 * inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点
 * https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
 */
/**
 * 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 {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    //pos:用于将树的中序遍历 位置与值 相映射,即哈希表,查找为O(1)
    let pos = {}
    for (let i = 0; i < inorder.length; i ++) {
        pos[inorder[i]] = i
    }
    return build(0, preorder.length - 1, 0, inorder.length - 1)

    // pl pr:前序的左右端点位置 il ir:中序的左右端点位置
    function build(pl, pr, il, ir) {
        //初始条件判断
        if (pl > pr) {
            return null
        }
        //以前序的最左端点为根节点,建立树
        let root = new TreeNode(preorder[pl])
        // k:根节点的位置
        let k = pos[root.val]
        //建立左子树(画图求端点表达式)
        root.left = build(pl + 1, pl + k - il, il, k - 1)
        //建立右子树
        root.right = build(pl + k - il + 1, pr, k + 1, ir)
        return root;
    }
};

树的哈希表映射:

let pos = {}
    for (let i = 0; i < inorder.length; i ++) {
        pos[inorder[i]] = i
    }

p108 将有序数组转换为二叉搜索树

/**
 * 题目描述:
 * 108. 将有序数组转换为二叉搜索树
 * 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
 * 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
 * https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/
 */

/**
 * 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 {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function (nums) {
    return build(0, nums.length - 1)

    function build(l, r) {
        //初始条件判断
        if (l > r) {
            return null
        }
        //以中间节点为根节点,建立二叉搜索树
        let mid = l + r >> 1
        let root = new TreeNode(nums[mid])
        //建立左子树
        root.left = build(l, mid - 1)
        //建立右子树
        root.right = build(mid + 1, r)
        return root
    }
};

p116 填充每个节点的下一个右侧节点指针

/**
 * 题目描述:
 * 116. 填充每个节点的下一个右侧节点指针
 * 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
 * struct Node {
 *   int val;
 *   Node *left;
 *   Node *right;
 *   Node *next;
 * }
 * 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
 * 初始状态下,所有next 指针都被设置为 NULL。
 * https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
 */

/**
 * // Definition for a Node.
 * function Node(val, left, right, next) {
 *    this.val = val === undefined ? null : val;
 *    this.left = left === undefined ? null : left;
 *    this.right = right === undefined ? null : right;
 *    this.next = next === undefined ? null : next;
 * };
 */

/**
 * @param {Node} root
 * @return {Node}
 * 思路:
 * 层次遍历,queue,每层将节点串联起来
 */
var connect = function(root) {
    let queue = []
    queue.push(root)
    if (root === null) {
        return root
    }
    while (queue.length > 0) {
        let n = queue.length
        //每层遍历时将该层的节点串联起来
        let node = queue[0]
        for (let i = 1; i < n; i ++) {
            node.next = queue[i]
            node = queue[i]
        }
        //遍历该层,将该层的左右节点放入queue
        for (let i = 0; i < n; i ++) {
            node = queue.shift()
            node.left && queue.push(node.left)
            node.right && queue.push(node.right)
        }
    }
    return root
};

p572 另一棵树的子树

/**
 * 572. 另一棵树的子树
 * 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
 * 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
 * https://leetcode-cn.com/problems/subtree-of-another-tree/
 */
/**
 * 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} s
 * @param {TreeNode} t
 * @return {boolean}
 * 思路:树哈希
 * 如果两棵树形态相同,哈希值相同;形态不同,哈希值大概率不同
 * (树哈希和字符串哈希一般不考虑冲突,因为冲突的概率非常小)
 */
var isSubtree = function(s, t) {
    //P Q:取一个较大的质数 MOD:用于取模,保证范围
    let P = 131, Q = 159, MOD = 1e4 + 7
    //S T:s t的哈希值(均设置为正数),子树t初始化为-1
    let S, T = -1
    //res:返回结果,默认false
    let res = false
    //求子树t的哈希值
    T = dfs(t)
    //如果t的哈希值和s的哈希值相同,说明t是s的子树
    if (T === dfs(s)) {
        res = true
    }
    return res

    //求以root为根节点的树的哈希值
    function dfs(root) {
        //如果根节点为空,随便返回一个不为0的值
        if (root === null) {
            return 12345
        }
        //求左子树、右子树的哈希值
        let left = dfs(root.left), right = dfs(root.right)
        //x:root根节点的哈希值
        let x = (root.val % MOD + MOD) % MOD
        //如果s的左右子树中如果有与t子树相同哈希值的,返回true
        if (left === T || right === T) {
            res = true
        }
        //返回:以root为根节点的树的哈希值
        return (x + left * P % MOD + right * Q) % MOD
    }
};

剑指offer

o33 二叉搜索树的后序遍历序列

/**
 * 剑指 Offer 33. 二叉搜索树的后序遍历序列
 * 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
 * https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
 */
/**
 * @param {number[]} postorder
 * @return {boolean}
 */
var verifyPostorder = function(postorder) {
  let seq = postorder
  return dfs(0, seq.length - 1)

  // l r当前序列的左右边界
  function dfs(l, r) {
    if (l >= r) return true
    let root = seq[r] // 根节点
    // 遍历找右子树的第一个节点
    let k = l
    while (k < r && seq[k] < root) k ++ // 此时k为右子树第一个节点
    // 遍历右子树
    for (let i = k; i < r; i ++) {
      // 如果右子树节点 < 根节点,返回false
      if (seq[i] < root) return false
    }
    // 继续递归左子树,右子树
    return dfs(l, k - 1) && dfs(k, r - 1)
  }
};

let num = [7, 4, 6, 5]
console.log(verifyPostorder(num))

o34 二叉树中和为某一值的路径

/**
 * 剑指 Offer 34. 二叉树中和为某一值的路径
 * 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
 * https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/
 */
/**
 * 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
 * @param {number} target
 * @return {number[][]}
 */
var pathSum = function(root, target) {
  let res = [], path = []
  dfs(root, target)
  return res

  function dfs(root, sum) {
    // 如果当前节点为空,则不是叶子结点
    if (! root) return
    path.push(root.val)
    sum -= root.val // 当sum减到0时,则为所求路径

    // 如果当前节点是叶子结点,同时sum=0,该路径加入到res中
    // 注意此处要用:path.slice(),以创建一个新数组的方式加入,否则结果是[[]]
    if (!root.left && !root.right && !sum) res.push(path.slice())
    // 递归遍历左右子树
    dfs(root.left, sum)
    dfs(root.right, sum)
    // 当前路径遍历完成后,恢复现场
    path.pop()
  }
};

o36 二叉搜索树与双向链表

/**
 * 剑指 Offer 36. 二叉搜索树与双向链表
 * 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
 */
/**
 * // Definition for a Node.
 * function Node(val,left,right) {
 *    this.val = val;
 *    this.left = left;
 *    this.right = right;
 * };
 */
/**
 * @param {Node} root
 * @return {Node}
 * 思路:中序遍历
 */
var treeToDoublyList = function(root) {
  let pre, head
  if (!root) return null
  dfs(root)

  // 遍历完成之后,此时pre指向的是尾结点
  // 循环双链表,首尾相连
  head.left = pre
  pre.right = head

  return head

  // 二叉搜索树,中序遍历是有序的
  function dfs(cur) {
    // 当前节点为空,返回
    if (!cur) return

    // 左子树
    dfs(cur.left)

    // 处理当前节点 pre:cur的左侧节点
    if(pre != null) pre.right = cur;
    else head = cur;
    cur.left = pre;
    pre = cur // pre后移

    // 右子树
    dfs(cur.right)
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值