● 654.最大二叉树
给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
- 创建一个根节点,其值为
nums
中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums
构建的 最大二叉树 。
思路
根据题目给出的递归算法,根据前序遍历 先找出最大值,创建根节点,然后递归创建根节点的左右子树即可
递归的三步曲:
确定参数与返回值
确定递归终止条件
确定单次递归的逻辑
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
TreeNode root = make(nums,0,nums.length-1);
return root;
}
public TreeNode make(int [] nums, int begin, int end){
if(begin > end) return null;
int max = nums[begin];
int index = begin;
for(int i = begin; i <= end; i++){
if(max < nums[i]){
max = nums[i];
index = i;
}
}
TreeNode root = new TreeNode(max);
root.left = make(nums, begin, index - 1);
root.right = make(nums, index + 1, end);
return root;
}
}
● 617.合并二叉树
给你两棵二叉树: root1
和 root2
。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
思路
依然是迭代的思路,并且依然前序;同时,若某一方为null 直接返回另一个,因为不需要合并了。
注:构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
TreeNode root = merge(root1, root2);
return root;
}
public TreeNode merge(TreeNode root1, TreeNode root2){
if(root1 == null && root2 == null) {
return null;
}
if(root1 == null){
return root2;
}
if(root2 == null){
return root1;
}
int val = root1.val + root2.val;
TreeNode root = new TreeNode(val);
root.left = merge(root1.left, root2.left);
root.right = merge(root1.right, root2.right);
return root;
}
}
● 700.二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点 root
和一个整数值 val
。
你需要在 BST 中找到节点值等于 val
的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null
。
思路
递归/迭代,因为是二叉搜索树,所以前序遍历
递归
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
TreeNode r = search(root, val);
return r;
}
public TreeNode search(TreeNode root, int val){
if(root == null || root.val == val){
return root;
}
TreeNode r = null;
if(root.val > val){
r = search(root.left, val);
}
if(root.val < val){
r = search(root.right, val);
}
return r;
}
}
迭代
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null){
return root;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
if(cur.val == val) return cur;
else if(cur.val < val){
if(cur.right != null){
stack.push(cur.right);
}else{
return null;
}
}else{
if(cur.left != null){
stack.push(cur.left);
}else{
return null;
}
}
}
return null;
}
}
● 98.验证二叉搜索树
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
思路
递归判断,但要注意,
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
因此,在比较root时需要将root的值与左侧最大比、与右侧最小比
要大于左侧最大,小于右侧最小
因此可以采用 递归套递归(利用递归寻找左、右子树的最值)
不过在看完题解后,发现这是一个比较笨的方法了
更快速的方法:
法 ① 中序遍历树,如果树是一个二叉搜索树,那么中序遍历的结果一定是递增的。
法② 递归,但修改单次递归的操作,上述方法的单次递归实际在做的是 判断左、右子树是不是二叉搜索树、判断当前子树是不是二叉搜索树。更加简便的思路是 中序遍历,找到最左下角的元素,记录是否递增,是则继续,否则return false
不太好的做法
class Solution {
public boolean isValidBST(TreeNode root) {
return judge(root);
}
public boolean judge(TreeNode root){
if(root == null) return true;
if(root.left == null && root.right == null) return true;
//此时root非空,left/right至少有一个非空
int val = root.val;
boolean b1 = true,b2 = true;
if(root.left != null){
if(val <= getmax(root.left)) return false;
b1 = judge(root.left);
}
if(root.right != null){
if(val >= getmin(root.right)) return false;
b2 = judge(root.right);
}
return b1 && b2;
}
public int getmax(TreeNode root){
if(root == null) return -1;
int max = root.val;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(root);
while(!que.isEmpty()){
int len = que.size();
for(int i = 0; i<len; i++){
TreeNode cur = que.poll();
if(cur.val > max){
max = cur.val;
}
if(cur.left != null) que.offer(cur.left);
if(cur.right != null) que.offer(cur.right);
}
}
return max;
}
public int getmin(TreeNode root){
if(root == null) return -1;
int max = root.val;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(root);
while(!que.isEmpty()){
int len = que.size();
for(int i = 0; i<len; i++){
TreeNode cur = que.poll();
if(cur.val < max){
max = cur.val;
}
if(cur.left != null) que.offer(cur.left);
if(cur.right != null) que.offer(cur.right);
}
}
return max;
}
}
法①判断是否递增
class Solution {
private:
vector<int> vec;
void traversal(TreeNode* root) {
if (root == NULL) return;
traversal(root->left);
vec.push_back(root->val); // 将二叉搜索树转换为有序数组
traversal(root->right);
}
public:
bool isValidBST(TreeNode* root) {
vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
traversal(root);
for (int i = 1; i < vec.size(); i++) {
// 注意要小于等于,搜索树里不能有相同元素
if (vec[i] <= vec[i - 1]) return false;
}
return true;
}
};
法②递归
class Solution {
// 递归
TreeNode max;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
// 左
boolean left = isValidBST(root.left);
if (!left) {
return false;
}
// 中
if (max != null && root.val <= max.val) {
return false;
}
max = root;//记录前一个节点
// 右
boolean right = isValidBST(root.right);
return right;
}
迭代
迭代模拟中序遍历即可
class Solution {
// 迭代
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;// 左
}
// 中,处理
TreeNode pop = stack.pop();
if (pre != null && pop.val <= pre.val) {
return false;
}
pre = pop;
root = pop.right;// 右
}
return true;
}
}