今日内容
- leetcode. 654 最大二叉树
- leetcode. 617 合并二叉树
- leetcode. 700 二叉搜索树中的搜索
- leetcode. 98 验证二叉搜索树
Leetcode. 654 最大二叉树
本题与前一天做的105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) 和106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) 思想类似。都是要找到一个“分水岭”后,再分别对其左右进行处理。
那么就直接按照这两题的解决思路进行处理。在构造二叉树的问题中,我们常用前序遍历解决,因为要先确定根节点后,再分别构造左右子树,这也是很符合我们的思维逻辑的。
本题代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
if (nums.length == 0){return null;}
TreeNode root = findMax(nums, 0, nums.length);
return root;
}
public TreeNode findMax(int[] nums, int start, int end){
if (start == end){return null;} // 没有元素了
int max = -1;
int delimeterIndex = 0;
// 寻找当前数组最大值
for (int i = start; i < end; i++){
if (nums[i] > max){
max = nums[i];
delimeterIndex = i;
}
}
TreeNode root = new TreeNode(max);
// 左右分割
int leftStart = start;
int leftEnd = delimeterIndex;
int rightStart = delimeterIndex + 1;
int rightEnd = end;
root.left = findMax(nums, leftStart, leftEnd);
root.right = findMax(nums, rightStart, rightEnd);
return root;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
Leetcode. 617 合并二叉树
本题思路就是同时遍历两棵二叉树,并将它们的结果覆盖到其中某一棵上。(当然,也可以新建一个二叉树记录结果)。
这样我们可以写出代码:
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
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;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
Leetcode. 700 二叉搜索树中的搜索
二叉搜索树的特点:
- 若左子树不空,则左子树上所有节点的值都比根节点的值小
- 若右子树不空,则右子树上所有节点的值都比根节点的值大
- 左右子树都是二叉搜索树
所以利用起搜索树的特点,本题要使用中序遍历。
思路就是看当前节点的值是否就是要找的值,不是的话比较大小。比目标值大就往左子树找,比目标值小就往右子树找。
代码如下:
// 递归法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val){return root;}
TreeNode n = new TreeNode();
if (root.val < val){
n = searchBST(root.right, val);
} else if (root.val > val){
n = searchBST(root.left, val);
} else {
return n;
}
return n;
}
}
// 迭代法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while (root != null){
if (root.val > val){
root = root.left;
} else if (root.val < val){
root = root.right;
} else {
return root;
}
}
return root;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
Leetcode. 98 验证二叉搜索树
一开始我的思路就是只比较根节点的值和其左右节点的值就好。但是这样就掉入“陷阱”了。因为二叉搜索树的定义是 左/右子树上所有节点的值都比根节点的值小/大。按照我一开始的思路只能保证某一个节点符合这个定义,但不能保证整个子树符合这个定义。
对于二叉搜索树,我们依然使用中序遍历。
解题思路就是:记录当前子树的根节点值,按照二叉搜索树特性,在中序遍历下,节点值应该不断递增。因此若出现某一节点值小于前一个节点,那么就不是二叉搜索树。
代码如下:
class Solution {
TreeNode pre = null; // 用于记录前一个节点的值
public boolean isValidBST(TreeNode root) {
if (root == null){return true;} // 二叉搜索树可以为空
boolean left = isValidBST(root.left);
if (pre != null && pre.val >= root.val){return false;} // 将当前节点值与前一个节点值进行比较
pre = root;
boolean right = isValidBST(root.right);
return left && right;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
根据二叉搜索树用中序遍历得到的节点值递增这一特性,我们还可以用中序遍历把二叉搜索树所有节点遍历出来,放到一个数组中。之后遍历数组,看看是否为递增数组。
代码如下:
// 查看数组是否递增
class Solution {
public boolean isValidBST(TreeNode root) {
List<Integer> list = new ArrayList<>();
findValid(root, list);
for (int i = 1; i < list.size(); i++){
if (list.get(i) <= list.get(i - 1)){
return false;
}
}
return true;
}
public void findValid(TreeNode node, List<Integer> list){
if (node == null){return;}
findValid(node.left, list);
list.add(node.val);
findValid(node.right, list);
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
总结
总是理解了思路,但是代码写出来就一堆小问题。不过确实感觉越做越顺了,起码不会像之前一样碰到题目毫无头绪。