文章简要概述
- 本文主要进行树相关的算法题刷题题解记录,记录树相关算法以及如何解。
- 这文一共有8道题,主要介绍leetcode中
二叉树的最大深度、面试题 04.05. 合法二叉搜索树、230. 二叉搜索树中第K小的元素、199. 二叉树的右视图、100. 相同的树、101. 对称二叉树、剑指 Offer 68 - I. 二叉搜索树的最近公共祖先和二叉树中的最大路径和的解题思路。
与树相关算法
104. 二叉树的最大深度
题目大意:
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例
给定二叉树
[3,9,20,null,null,15,7],3 / \ 9 20 / \ 15 7
解题思路:
- 采用深度优先搜索、广度优先搜索都可以实现
- 递归的方式,获取左右子树高度的最大值,再+1就是当前树的高度
代码:
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if (root === null) return 0
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
};
面试题 04.05. 合法二叉搜索树
题目大意:
实现一个函数,检查一棵二叉树是否为二叉搜索树。
示例:
输入:
2
/ \
1 3
输出: true
解题思路:
- 二叉搜索树的规律是,根节点的值大于左子树的值,右子树的值大于根节点
- 遍历树,比较上面的规律,不符合即返回false
- 当遍历到空节点说明之前都是符合条件,即返回true
代码:
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isValidBST = function(root) {
return helper(root, -Infinity, Infinity)
};
function helper(root, lower, upper) {
if (root === null) return true;
if (root.val <= lower || root.val >= upper) return false;
return helper(root.left, lower, root.val) && helper(root.right, root.val, upper);
}
230. 二叉搜索树中第K小的元素
题目大意:
给定一个二叉搜索树的根节点 `root` ,和一个整数 `k` ,请你设计一个算法查找其中第 `k` ****个最小元素(从 1 开始计数)。
示例:
输入: root = [3,1,4,null,2], k = 1
输出: 1
解题思路:
- 二叉搜索树的规律是左子树的值是当前树中值最小的值
- 借助栈,先遍历左子树,放入到栈中
- 弹栈,当k值为0。即找到第k小的值,否则把右子树放入到栈中
- 循环操作直到符合k的值
代码:
/**
* @param {TreeNode} root
* @param {number} k
* @return {number}
*/
var kthSmallest = function(root, k) {
let stack = [];
while(root !== null || stack.length) {
while(root!== null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
k--;
if (k === 0) {
break;
}
root = root.right;
}
return root.val
};
199. 二叉树的右视图
题目大意:
给定一个二叉树的 **根节点** `root`,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
解题思路:
- 找到树结构的每一层,寻找到最右侧的节点
- 设置一个栈,存储每一层最右侧的值
- 优先递归遍历右子树,当层数和栈的长度一致时,将当前节点放入到栈中
- 递归完成,返回栈即可
代码:
/**
* @param {TreeNode} root
* @return {number[]}
*/
var rightSideView = function(root) {
let res = [];
function dsf(root, deph) {
if (!root) return [];
if (deph === res.length) {
res.push(root.val);
}
deph++
dsf(root.right, deph);
dsf(root.left, deph);
}
dsf(root, 0)
return res
};
100. 相同的树
题目大意:
给你两棵二叉树的根节点 `p` 和 `q` ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例:
输入: p = [1,2,3], q = [1,2,3] 输出: true
解题思路:
- 比较当前节点的值是否都为空,如果都为空,说明之前遍历都是符合条件的,即返回true
- 当前节点的值,其中一个为空,即两个节点不相同,返回false
- 当前节点的值不相等,即两个节点不相同,返回false
- 以上条件都符合,递归遍历两棵树,继续比较左子树与左子树,右子树与右子树的值
代码:
/**
* @param {TreeNode} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function(p, q) {
if (p === null && q === null) return true;
else if (p == null ||q == null) return false;
else if (p.val !== q.val) return false;
else return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
};
101. 对称二叉树
题目大意:
给你一个二叉树的根节点 `root` , 检查它是否轴对称。
示例:
输入: root = [1,2,2,3,4,4,3]
输出: true
解题思路:
- 对称二叉树,即可得到左子树与右子树的值相同
- 将树的左子树与右子树进行比较
- 当都为空时,说明前面递归比较都符合条件,即返回true
- 当其中一个为空时,不符合两个节点相等,即返回false
- 当两个节点相等,继续递归比较左子树与右子树的值是否相同
代码:
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function(root) {
return check(root, root);
};
function check(p, q) {
if (q == null && p == null) return true;
if (!q || !p) return false;
return p.val === q.val && check(p.left, q.right) && check(p.right, q.left);
}
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先--leetcode
题目大意:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
解题思路:
- 当前树是二叉搜索树,即左子树的值小于根节点小于右子树的值
- 当p的值小于根节点的值,且q的值也小于根节点的值。即p和q的最近公共祖先在根节点左子树中
- 当p的值大于根节点的值,且q的值也大于根节点的值。即p和q的最近公共祖先在根节点右子树中
- 否则,当前节点就是最近公共祖先
代码:
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
while(root) {
if (p.val < root.val && q.val < root.val) {
root = root.left;
} else if (p.val > root.val && q.val > root.val) {
root = root.right;
} else {
break;
}
}
return root;
};
124. 二叉树中的最大路径和
题目大意:
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
示例:
输入:root = [-10,9,20,null,null,15,7] 输出:42 解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
解题思路:
- 先遍历左侧:Math.max(0,traverse(node.left));
- 再遍历右侧:Math.max(0,traverse(node.right));
- 在每个节点执行更新max:如果这条链路(左最大+右最大+当前节点值)比之前的max大,则更新max:Math.max(max,left+right+node.val)
- 在每个节点返回当前节点的最大值和(可能在左侧,也可能在右侧):Math.max(left,right)+node.val
代码:
/**
* @param {TreeNode} root
* @return {number}
*/
var maxPathSum = function(root) {
let max = root.val;
const traverse = (node)=>{
if(node !== null){
const left = Math.max(0,traverse(node.left));//左侧遍历
const right = Math.max(0,traverse(node.right));//右侧遍历
max = Math.max(max,left+right+node.val);//更新max
return Math.max(left,right)+node.val//返回当前链路和
}
return 0
}
traverse(root);
return max
};
结束语
数据结构与算法相关的练习题会持续输出,一起来学习,持续关注。当前是树部分。后期还会有其他类型的数据结构,题目来源于leetcode。往期文章:
树形结构-对应算法详解一 树形结构-对应算法详解二 链表相关算法复习一
链表相关算法复习二 链表相关算法复习三 数据结构与算法-栈一
数据结构与算法-栈二 数据结构与算法-队列一 数据结构与算法-队列二
数据结构与算法-链表一 数据结构与算法-链表二 数据结构与算法-链表三
有兴趣的可以一起来刷题,求点赞👍 关注!