文档讲解: 代码随想录
视频讲解: 《代码随想录》算法公开课-跟着Carl学算法
LeetCode654.最大二叉树
题目链接:654.最大二叉树
思路(后续优化,每次递归不需要创建新数组,在原数组基础上传递下标):与上道题同样的思路,以数组最大值进行分割,左侧为根节点左子树,右侧为根节点的右子树,然后进行递归。
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
if (nums.length == 0) {
return null;
}
// 找到数组里的最大值作为根节点
int maxNum = Arrays.stream(nums).max().getAsInt();
TreeNode root = new TreeNode(maxNum);
if (nums.length == 1) {
return root;
}
int index = getIndex(nums, maxNum);
// 以根节点为切割点
int[] left = Arrays.copyOfRange(nums, 0, index);
int[] right = Arrays.copyOfRange(nums, index + 1, nums.length);
// 递归遍历左右子树
root.left = constructMaximumBinaryTree(left);
root.right = constructMaximumBinaryTree(right);
return root;
}
public static int getIndex(int[] arr, int value) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return -1;// 如果未找到返回-1
}
}
LeetCode617.合并二叉树
题目链接:617.合并二叉树
思路:就按照LeetCode题目思路来做就可以。构造二叉树我们还是采用前序遍历。确定遍历顺序后,我们讨论递归三部曲:
- 传入参数和返回值:形参为两个二叉树的节点,返回值为处理后的节点。
- 终止条件:如果遍历到两个二叉树某个位置时,节点都为null,则返回空
- 单层递归逻辑:如果某个二叉树的节点为空,直接返回另一个二叉树节点的值。除了都为空或者单个为空两种情况,剩下的就是两个二叉树同一位置的节点都不为空,直接相加。然后进行左子树和右子树的递归。
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
// 前序遍历:中 左 右
// 终止条件:两个节点都为空
if (root1 == null && root2 == null) {
return null;
}
// 单层递归逻辑:
// 直接将节点值相加
// 其中一个没有时直接作为新二叉树的节点
if (root1 == null) {
return root2;
}
if (root2 == null) {
return root1;
}
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
}
}
LeetCode700.二叉搜索树中的搜索
题目链接:700.二叉搜索树中的搜索
题目描述:给定二叉搜索树(BST)的根节点 root 和一个整数值 val。你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
思路:二叉搜索树符合左小右大,所以就间接确定了递归遍历的顺序。如果此时root值大于val,则向左子树去搜索;若root值小于val,就向右子树去搜索;当root值等于val,终止并返回以该节点为根的子树,否则返回空;一刷没有注意的点是递归要return,要接住此时的root,否则退出当前递归这个值就消失了!
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
// 前序遍历
// 二叉搜索树 左小右大
// 如果root值大于val 向左子树搜索
// 如果root值小于val 就向右子树搜索
// 终止条件:root值等于val 返回以该节点为根的子树 否则为空
if (root == null) {
return null;
}
if (root.val == val) {
return root;
}
if (root.val > val) {
return searchBST(root.left, val);
} else {
return searchBST(root.right, val);
}
}
}
LeetCode98.验证二叉搜索树
题目链接:98.验证二叉搜索树
题目描述:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
思路:先自己思考的时候确实陷入了一个误区,认为在递归的时候将中间节点和左右子节点比较大小,满足左小右大的规则就可以,后面看了随想录确实有反例,二叉搜索树的满足的条件是:根节点的要大于整个左子树,小于整个右子树;所以说之前的想法属实是偷换概念了。随想录的思想看懂之后感觉还是挺简单的,但是第一次做这道题自己确实没想出来。首先确定递归顺序,根据二叉搜索树的定义,用中序遍历最合适。为什么?中序遍历的顺序就是左中右,所以按照这个遍历顺序,整个遍历过程是升序的,我们后面只需要判断每次遍历的节点是否比前一个节点大就可以,非常方便!所以首先在代码中设置了全局变量preNode = null,这个节点始终是root节点的前一位,同时在遍历的过程中与root节点同时移动,类似数组里的双指针。整体思路讨论完之后,下面讨论递归三部:
- 传入参数和返回值:传入参数为根节点,返回值为布尔类型,用来判断是否是二叉搜索树。
- 终止条件:当递归到空节点的时候,则返回true
- 单层递归逻辑:先处理左子树,将左子节点进行递归。然后处理中间节点,当preNode的值大于等于当前root的值时,就证明已经不是二叉搜索树了,我们就返回false;反之,则进一步进行递归,然后把preNode节点更新,让其始终为root节点的前一位;这里其实隐含着一个注意点。我们能不能在 if 判断中写preNode的值小于root的值,条件满足则对preNode节点更新,否则返回false,这种写法是不行的!因为我们初始时preNode赋值空节点,若用上述这种写法不会进入到条件判断语句体,直接会返回false,显然不对!所以这里要额外注意!然后正常递归处理右子树,最终函数的返回值是 left && right,当左子树和右子树同时满足真时此时才是二叉搜索树!
class Solution {
TreeNode preNode = null; // 定义空节点初始化
public boolean isValidBST(TreeNode root) {
// 直观来看用中序遍历应该可以吧? 左 中 右 看遍历结果是否是升序的
// 终止条件
if (root == null) {
return true;
}
// 左子树
boolean left = isValidBST(root.left);
// 中间节点
// 递归过程中保证preNode节点始终是root的前一个节点
// 比较两个节点的值
if (preNode != null && preNode.val >= root.val) {
return false;
}
preNode = root; // 这里的逻辑很重要 如果条件判断preNode.val < root.val 逻辑不对 只能这么写
// 右子树
boolean right = isValidBST(root.right);
return left && right;
}
}