代码随想录一刷(2024-01-23 ~ 2024-01-26)
1.二叉树的构造
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;
}
}
2.二叉树的前中后序遍历(深度优先遍历)
方法一:递归法
/**
* 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 List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root, res);
return res;
}
public void preorder(TreeNode root, List<Integer> res){
if(root == null) return;
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
}
//中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res){
if(root == null) return;
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
//后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> res){
if(root == null) return;
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
方法二:迭代法
前序遍历
/**
* 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 List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
res.add(node.val);
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
return res;
}
}
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> st = new Stack<>();
TreeNode cur = root;
while(cur != null || !st.isEmpty()){
if(cur != null){
st.push(cur);
cur = cur.left;
}else{
cur = st.pop();
res.add(cur.val);
cur = cur.right;
}
}
return res;
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> st = new Stack<>();
st.push(root);
while(!st.isEmpty()){
TreeNode cur = st.pop();
res.add(cur.val);
if(cur.left != null) st.push(cur.left);
if(cur.right != null) st.push(cur.right);
}
Collections.reverse(res);//反转数组
return res;
}
}
3.二叉树的层序遍历
方法一:递归法
//递归法!!!!!
class Solution {
List<List<Integer>> res = new ArrayList<List<Integer>>();
public void order(TreeNode node, int deep){
if(node == null) return;//当根节点为空时结束递归
deep ++;//元素属于第deep层,放在第deep-1个cur里;
if(res.size() < deep){//用size和deep之间的关系限制要不要再加一层
List<Integer> cur = new ArrayList<Integer>();//其实就是层数
res.add(cur);
}
res.get(deep - 1).add(node.val);//选择相应的层数加进去
order(node.left, deep);//递归左子结点
order(node.right, deep);//递归右子结点
}
public List<List<Integer>> levelOrder(TreeNode root) {
order(root, 0);
return res;
}
}
方法二:利用队列来进行遍历(迭代)
ArrayList适用于频繁查询和随机访问的场景,而LinkedList适用于频繁插入、删除和位置变动较多的场景
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);//先把第一层的放进队列里面
while(!q.isEmpty()){
List<Integer> cur = new ArrayList<Integer>();//每次循环就建立新的一层
int size = q.size();//用来记录每一层要放的值(也就是每次循环之后,队列里还剩的数的个数)
while(size > 0){
TreeNode temp = q.poll();
cur.add(temp.val);//把数放进它所在层的cur中
if(temp.left != null) q.offer(temp.left);//把这个数的左子节点放进队列
if(temp.right != null) q.offer(temp.right);//这个数的右子节点放进队列
size --;//每把一个数放进cur中,size就减1
}
res.add(cur);//把每一层放进答案里面
}
return res;
}
}
在上面代码的基础上加上下面一段代码(即翻转)
List<List<Integer>> res2 = new ArrayList<List<Integer>>();
for(int i = res.size() - 1; i >= 0; i --){
res2.add(res.get(i));
}
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
//因为是一起输出来,所以不用每次都建立新的一层
int size = q.size();
for(int i = 0; i < size; i ++){
TreeNode temp = q.poll();
if(temp.left != null) q.offer(temp.left);
if(temp.right != null) q.offer(temp.right);
if(i == size - 1) res.add(temp.val);//只输出每层的最后一个元素就行
}
}
return res;
}
}
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
if(root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
double sum = 0.0;
int size = q.size();
int s1 = size;
while(size > 0){
TreeNode temp = q.poll();
if(temp.left != null) q.offer(temp.left);
if(temp.right != null) q.offer(temp.right);
sum += temp.val;
size --;
}
res.add(sum / s1);//每层求出平均值加进去就行
}
return res;
}
}
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null) return res;
Queue<Node> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
List<Integer> levelres = new ArrayList<Integer>();
int size = q.size();
for(int i = 0; i < size; i ++){
//这里最好用for循环,不要用while
Node temp = q.poll();
levelres.add(temp.val);
List<Node> children = temp.children;//就只有这里变了,一个节点有多个孩子
if(children == null || children.size() == 0) continue;
for(Node child : children){
if(child != null) q.offer(child);
}
}
res.add(levelres);
}
return res;
}
}
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if(root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
int size = q.size();
int max = Integer.MIN_VALUE;//因为要求最大值,所以先把int类型的最小取值数赋给max
for(int i = 0; i < size; i ++){
TreeNode temp = q.poll();
max = temp.val > max ? temp.val : max;
if(temp.left != null) q.offer(temp.left);
if(temp.right != null) q.offer(temp.right);
}
res.add(max);
}
return res;
}
}
class Solution {
public Node connect(Node root) {
Queue<Node> q = new LinkedList<>();
if(root == null) return root;
q.offer(root);
while(!q.isEmpty()){
int size = q.size();
Node cur = q.poll();//这里的cur都是每一层的第一个
if(cur.left != null) q.offer(cur.left);//要先把左右孩子放进队列,后面才能建立联系
if(cur.right != null) q.offer(cur.right);
for(int i = 1; i < size; i ++)//这里只循环size-1次(假如这一层有n个元素,那么只要建立n-1个联系就好了)
{
Node next = q.poll();
if(next.left != null) q.offer(next.left);//把左右孩子放进队列,后面才能找到下一层元素
if(next.right != null) q.offer(next.right);
cur.next = next;
cur = next;
}
}
return root;
}
}
class Solution {
public Node connect(Node root) {
Queue<Node> q = new LinkedList<>();
if(root != null) q.offer(root);
while(!q.isEmpty()){
int size = q.size();
Node cur = null;
Node next = null;
for(int i = 0; i < size; i ++){
if(i == 0){
cur = q.poll();
next = cur;
}else{
next = q.poll();
cur.next = next;
cur = next;
}
if(cur.left != null) q.offer(cur.left);
if(cur.right != null) q.offer(cur.right);
}
cur.next = null;//这一层的最后一个数指向null
}
return root;
}
}
4.翻转二叉树
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
swap(root);//只需要在遍历二叉树的基础上,加上左右孩子节点交换就行
invertTree(root.left);
invertTree(root.right);
return root;
}
public void swap(TreeNode root){
TreeNode t = root.left;
root.left = root.right;
root.right = t;
}
}
5.对称二叉树
class Solution {
public boolean isSymmetric(TreeNode root) {
return compare(root.left, root.right);
}
public boolean compare(TreeNode left, TreeNode right){
//先把终止情况先列出来,一共有五种(要用后序遍历)
if(left == null && right != null) return false;//左孩子为空,右孩子不为空
if(left != null && right == null) return false;//右孩子为空,左孩子不为空
if(left != null && right != null && left.val != right.val) return false;//都不为空,但是值不相等
if(left == null && right == null) return true;//左右都为空
//还有一种是左右孩子的值都相等,就继续往下遍历
boolean outside = compare(left.left, right.right);//判断外侧孩子是否对称
boolean inside = compare(left.right, right.left);//判断内侧孩子是否对称
return inside && outside;//把结果返回父节点
}
}
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
return compare(p, q);
}
public boolean compare(TreeNode p, TreeNode q){
if(p != null && q == null) return false;
if(p == null && q != null) return false;
if(p != null && q != null && p.val != q.val) return false;
if(p == null && q == null) return true;
boolean left = compare(p.left, q.left);//和101对称二叉树相同,把左孩子和左孩子比较
boolean right = compare(p.right, q.right);//右孩子和右孩子比较
return left && right;
}
}
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(subRoot == null) return true;//subRoot为null一定都是true
if(root == null) return false;//root为null一定都是false
//1.递归左子树判断是否相等
//2.递归右子树,判断是否相等
//3.就根节点开始比较
//只要这三种情况有一种成立,就返回true
return isSubtree(root.right, subRoot) || isSubtree(root.left, subRoot) || compare(root, subRoot);
}
public boolean compare(TreeNode p, TreeNode q){
//下面的代码和前面几题都一样,都是比较一棵树是否相等
if(p == null && q == null) return true;
if(p != null && q == null) return false;
if(p == null && q != null) return false;
if(p != null && q != null && p.val != q.val) return false;
boolean left = compare(p.left, q.left);
boolean right = compare(p.right, q.right);
return left && right;
}
}
6.二叉树的最大、最小深度
最大深度
方法一:迭代法(层序遍历)
class Solution {
public int maxDepth(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
int h = 0;
if(root == null) return h;
q.offer(root);
while(!q.isEmpty()){
int size = q.size();
while(size > 0){
TreeNode cur = q.poll();
if(cur.left != null) q.offer(cur.left);
if(cur.right != null) q.offer(cur.right);
size --;
}
h ++;//每循环一层,深度加1
}
return h;
}
}
方法二:递归法
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;//知道root为空,就返回0
//找出左右子树最大深度的一边 深度再加1
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
方法一:层序遍历
class Solution {
public int maxDepth(Node root) {
Queue<Node> q = new LinkedList<>();
int h = 0;
if(root == null) return h;
q.offer(root);
while(!q.isEmpty()){
h ++;
int size = q.size();
for(int i = 0; i < size; i ++){
Node cur = q.poll();
List<Node> children = cur.children;
if(children == null || children.size() == 0) continue;
for(Node child : children)
if(child != null) q.offer(child);
}
}
return h;
}
}
方法二:递归
class Solution {
public int maxDepth(Node root) {
if(root == null) return 0;
int depth = 0;
if(root.children != null){
for(Node child : root.children){
depth = Math.max(depth, maxDepth(child));//循环每个孩子节点,找到最大那个
}
}
return depth + 1;//后序遍历(返回给父节点)
}
}
最小深度
方法一:层序遍历(迭代法)
class Solution {
public int minDepth(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
int h = 0;
if(root == null) return h;
q.offer(root);
while(!q.isEmpty()){
h ++;
int size = q.size();
while(size > 0){
TreeNode cur = q.poll();
if(cur.left == null && cur.right == null) return h;//如果当前节点的左右孩子都为空,那就直接返回最小深度
if(cur.left != null) q.offer(cur.left);
if(cur.right != null) q.offer(cur.right);
size --;
}
}
return h;
}
}
方法二:递归法
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
int leftdepth = minDepth(root.left);
int rightdepth = minDepth(root.right);
if(root.left == null) return rightdepth + 1;//左子树为空,右子树不为空,最小深度是1+右子树的深度
if(root.right == null) return leftdepth + 1;//右子树为空,左子树不为空,最小深度是1+左子树的深度
return Math.min(leftdepth, rightdepth) + 1;//左右子树都不为空,返回左右子树深度最小值+1
}
}
7.完全二叉树的节点个数
222. 完全二叉树的节点个数 - 力扣(LeetCode)
方法一:递归法
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
return countNodes(root.left) + countNodes(root.right) + 1; //自身的结点1 加上左右子树的节点总数
}
}
方法二:层序遍历(迭代法)
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int result = 0;//用来记录点的个数
while(!q.isEmpty()){
int size = q.size();
while(size > 0){
TreeNode temp = q.poll();
result ++;
if(temp.left != null) q.offer(temp.left);
if(temp.right != null) q.offer(temp.right);
size --;
}
}
return result;
}
}
方法三:利用完全二叉树本身的性质
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
TreeNode left = root.left;//先把左右子树分开
TreeNode right = root.right;
int leftdepth = 0, rightdepth = 0;
while(left != null){
left = left.left;//沿最左侧不断往下
leftdepth ++;
}
while(right != null){
right = right.right;//沿最右侧不断往下
rightdepth ++;
}
//如果左右两侧深度相等,那么说明这是满二叉树
//满二叉树的结点数为:2^depth - 1
if(rightdepth == leftdepth) return (2 << leftdepth) - 1;// 2<<1 等同于 2^2
return countNodes(root.left) + countNodes(root.right) + 1;//左子树的结点数+右子树的结点数+自身的1
}
}
二叉树节点的深度与高度(概念)
深度:从根节点到该节点的最长简单路径边的条数
高度:从该节点到叶子节点的最长简单路径边的条数
求深度用前序遍历:是一直向下遍历的,不需要向上返回结果
求高度用后序遍历:因为是要从左右子节点开始算起,返回父节点,最终返回给根节点(左右中)
8.平衡二叉树的判断
递归法(使用后序遍历,将左右子树的结果返回给父节点)
class Solution {
public boolean isBalanced(TreeNode root) {
//返回值为0和树的高度 都说明是平衡二叉树
//返回值为-1,说明不是平衡二叉树
return getHeight(root) != -1;
}
public int getHeight(TreeNode root){
if(root == null) return 0;//节点为空直接返回0,这里不单指根节点
//判断左子树是不是平衡二叉树
//如果是的话,就求出左子树的高度,并返回
//左子树就不是平衡二叉树了,就直接返回-1
int leftHeight = getHeight(root.left);
if(leftHeight == -1) return -1;
//求出右子树的高度
//或者右子树就不是平衡二叉树了
int rightHeight = getHeight(root.right);
if(rightHeight == -1) return -1;
//左右子树的高度差超过1,就不是平衡二叉树,返回-1
if(Math.abs(leftHeight - rightHeight) > 1) return -1;
//求出树的高度
return Math.max(leftHeight, rightHeight) + 1;
}
}
9.二叉树与路径有关的题目
使用前序遍历(父节点指向孩子节点,才能把路径输出)
方法一:递归法
1. toString() Java toString() 方法 | 菜鸟教程 (runoob.com)
2. append() JAVA中的append()方法_append java-CSDN博客
3.StringBuilder() Java StringBuffer 和 StringBuilder 类 | 菜鸟教程 (runoob.com)
class Solution {
List<String> result = new ArrayList<>();
public List<String> binaryTreePaths(TreeNode root) {
path(root, "");
return result;
}
public void path(TreeNode root, String s){
if(root == null) return;//根节点为空直接返回
if(root.left == null && root.right == null)//当节点没有左右孩子,说明到了叶子节点
{
//直接把前面的路径字符串加上当前叶子节点就行
result.add(new StringBuilder(s).append(root.val).toString());
return;
}
String temp = new StringBuilder(s).append(root.val).append("->").toString();
//把前面的公共路径temp传进函数,然后再分开左右结点进行遍历
path(root.left, temp);//遍历左边结点
path(root.right, temp);//遍历右边结点
}
}
方法二:迭代法
1.Object 类 Java Object 类 | 菜鸟教程 (runoob.com)
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> result = new ArrayList<>();
if(root == null) return result;
Stack<Object> st = new Stack<>();
st.push(root);
st.push(root.val + "");
while(!st.isEmpty()){
String path = (String)st.pop();//取出节点路径(根节点到当前节点)
TreeNode temp = (TreeNode)st.pop();//取出当前节点
//如果找到叶子结点,那就直接把路径放进结果里面
if(temp.left == null && temp.right == null) result.add(path);
//先进右再进左,才能先出左后出右
if(temp.right != null)//右子节点不为空
{
st.push(temp.right);//把现在的节点放进栈中
st.push(path + "->" + temp.right.val);//路径加上当前节点
}
if(temp.left != null)//左子节点不为空
{
st.push(temp.left);//把现在的节点放进栈中保存起来
st.push(path + "->" + temp.left.val);//当前节点放进路径里面
}
}
return result;
}
}
方法一:迭代法
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) return false;
Stack<Object> st = new Stack<>();
st.push(root);
st.push(root.val);
while(!st.isEmpty()){
int sum = (int)st.pop();
TreeNode temp = (TreeNode)st.pop();
if(temp.left == null && temp.right == null && sum == targetSum) return true;
if(temp.right != null){
st.push(temp.right);
st.push(sum + temp.right.val);
}
if(temp.left != null){
st.push(temp.left);
st.push(sum + temp.left.val);
}
}
return false;
}
}
方法二:递归法
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) return false;//根节点为空,返回false
if(root.left == null && root.right == null) return root.val == targetSum;//叶子节点判断
//只要左右有一条成立就行,总目标值要减去当前节点值(这是属于已经走过的路)在进行递归
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
1.removeLast Java.util.LinkedList.removeLast() 方法 (w3schools.cn)
2.result.add(new LinkedList<>(path))力扣77题关于result.add(new LinkedList<>(path))的解释_result.add(new arraylist<>(path))-CSDN博客
class Solution {
List<List<Integer>> result;
List<Integer> path;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
result = new LinkedList<>();
path = new LinkedList<>();
sum(root, targetSum);
return result;
}
public void sum(TreeNode root, int targetSum){
if(root == null) return;
path.add(root.val);
targetSum -= root.val;
if(root.left == null && root.right == null && targetSum == 0)
result.add(new LinkedList<>(path));
sum(root.left, targetSum);
sum(root.right, targetSum);
path.removeLast();//回溯(会重复多次)
}
}
10.左叶子之和
404. 左叶子之和 - 力扣(LeetCode)
方法一:递归法
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) return 0;
int leftValue = sumOfLeftLeaves(root.left);//当前节点的左孩子的左叶子结点
int rightValue = sumOfLeftLeaves(root.right);//当前节点的右孩子的左叶子节点
int midValue = 0;//当前节点的左叶子节点
if(root.left != null && root.left.left == null && root.left.right == null) midValue = root.left.val;
return midValue + rightValue + leftValue;
}
}
方法二:迭代法(前序遍历)
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) return 0;
Stack<TreeNode> st = new Stack<>();
st.push(root);//把根节点放进栈中
int result = 0;
while(!st.isEmpty()){
TreeNode temp = st.pop();//每次取出一个结点进行遍历(这样就可以遍历完这棵树了)
//还是那个判断条件
if(temp.left != null && temp.left.left == null && temp.left.right == null){
result += temp.left.val;
}
if(temp.left != null) st.push(temp.left);//把父节点的左孩子放进栈中(如果左孩子不为空)
if(temp.right != null) st.push(temp.right);
}
return result;
}
}
方法三:层序遍历(迭代法)
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int result = 0;
if(root == null) return result;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while(!q.isEmpty()){
int size = q.size();
while(size > 0){
TreeNode temp = q.poll();//遍历了每个节点
if(temp.left != null){
q.offer(temp.left);//把当前节点的左节点加进队列,如果不为空的话
if(temp.left.left == null && temp.left.right == null){
result += temp.left.val;
}
}
if(temp.right != null) q.offer(temp.right);//右节点加进队列
size --;
}
}
return result;
}
}
11.树左下角的值
适合用层序遍历
class Solution {
public int findBottomLeftValue(TreeNode root) {
//题目限定了至少有一个结点,所以不用判断root为空的情况
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int res = 0;
while(!q.isEmpty()){
int size = q.size();
for(int i = 0; i < size; i ++){
TreeNode temp = q.poll();
if(i == 0) res = temp.val;//i=0是每层的最左边,i会不断的被覆盖,直到是最后一层的最左边
if(temp.left != null) q.offer(temp.left);
if(temp.right != null) q.offer(temp.right);
}
}
return res;
}
}
12.从中序与(前、后)序遍历序列构造二叉树
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {
Map<Integer, Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>();//保存中序序列中数值以及其相对应的位置
for(int i = 0; i < inorder.length; i ++){
map.put(inorder[i], i);
}
//所有的范围都要统一原则:满足左闭右开
return findNode(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
public TreeNode findNode(int[] inorder, int inFirst, int inEnd, int[] postorder, int postFirst, int postEnd){
if(inEnd <= inFirst || postEnd <= postFirst) return null;//不满足左闭右开,没有元素,就返回
int rootIndex = map.get(postorder[postEnd - 1]);//从后序序列中找到根节点,求出它在中序序列中的位置
TreeNode root = new TreeNode(inorder[rootIndex]);//建立根节点
int leftLength = rootIndex - inFirst;//求出左区间的长度
//求左孩子
root.left = findNode(inorder, inFirst, rootIndex, postorder, postFirst, postFirst + leftLength);
//求右孩子
root.right = findNode(inorder, rootIndex + 1, inEnd, postorder, postFirst + leftLength, postEnd - 1);
return root;
}
}
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {
Map<Integer,Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
map = new HashMap<>();
for(int i = 0; i < inorder.length; i ++){
map.put(inorder[i], i);
}
return findNode(inorder, 0, inorder.length, preorder, 0, preorder.length);
}
public TreeNode findNode(int[] inorder, int inFirst, int inEnd, int[] preorder, int preFirst, int preEnd){
if(inEnd <= inFirst || preEnd <= preFirst) return null;
int nodeIndex = map.get(preorder[preFirst]);
TreeNode root = new TreeNode(inorder[nodeIndex]);
int leftLength = nodeIndex - inFirst;
root.left = findNode(inorder, inFirst, nodeIndex, preorder, preFirst + 1, preFirst + leftLength + 1);
root.right = findNode(inorder, nodeIndex + 1, inEnd, preorder, preFirst + leftLength + 1, preEnd);
return root;
}
}
相关题目
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructMaximumBinaryTree1(nums, 0, nums.length);
}
public TreeNode constructMaximumBinaryTree1(int[] nums, int first, int end){
if(first >= end) return null;//为空,或者不满足左闭右空原则
if(first + 1 == end) return new TreeNode(nums[first]);//只有一个元素
int maxIndex = first;//先把它赋给第一个
int max = nums[maxIndex];
for(int i = first + 1; i < end; i ++)//循环比较可以从第二个元素开始
{
if(max < nums[i]){
maxIndex = i;
max = nums[i];
}
}
TreeNode root = new TreeNode(max);
//根据maxIndex划分左右区间
root.left = constructMaximumBinaryTree1(nums, first, maxIndex);
root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, end);
return root;
}
}
13.合并二叉树
方法一:递归法
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) return root2;//如果树1结点为空,直接返回树2
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;
}
}
方法二:使用队列迭代
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) return root2;
if(root2 == null) return root1;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root1);
q.offer(root2);
while(!q.isEmpty()){
TreeNode node1 = q.poll();//队列先进先出
TreeNode node2 = q.poll();
//此时两个节点一定不为空
node1.val += node2.val;
//两数的左节点不为空,加入队列
if(node1.left != null && node2.left != null){
q.offer(node1.left);
q.offer(node2.left);
}
//两数的右节点不为空,加入队列
if(node1.right != null && node2.right != null){
q.offer(node1.right);
q.offer(node2.right);
}
//树1的左节点为空,直接把树2的左节点赋值给它
if(node1.left == null && node2.left != null){
node1.left = node2.left;
}
//树1的右节点为空,直接把树2的右节点赋值给它
if(node1.right == null && node2.right != null){
node1.right = node2.right;
}
//还有一种情况是树1有,树2为空,但由于返回的是树1,所以这种情况不用考虑(已经在那里了)
}
return root1;
}
}
14.二叉搜索树的搜索
方法一:递归法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null || root.val == val) return root;
//利用二叉搜索树的特点,小的在左边,大的在右边
if(root.val > val) return searchBST(root.left, val);
else return searchBST(root.right, val);
}
}
方法二:迭代法
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 null;
}
}
15.验证二叉搜索树
方法一:递归法
class Solution {
public boolean isValidBST(TreeNode root) {
//这里不能用Integer.MAX_VALUE,会报错
return check(root, Long.MAX_VALUE, Long.MIN_VALUE);
}
public boolean check(TreeNode root, long upper, long lower){
if(root == null) return true;
if(root.val <= lower || root.val >= upper) return false;
return check(root.left, root.val, lower) && check(root.right, upper, root.val);
}
}
方法二:迭代法(利用二叉搜索树与中序遍历相似的特点)
class Solution {
private long temp = Long.MIN_VALUE;//记得这个temp要在函数外面定义!!!而且要定义成long类型的,int会报错
public boolean isValidBST(TreeNode root) {
//根据二叉搜索树的定义可以想到中序遍历(它们的大小关系是左<中<右)
if(root == null) return true;
if(!isValidBST(root.left)) return false;
if(temp >= root.val) return false;//
temp = root.val;
return isValidBST(root.right);
}
}
16.二叉搜索树的最小绝对差
530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)
方法一:递归法
class Solution {
TreeNode temp;
int result = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root == null) return 0;
minGet(root);
return result;
}
public void minGet(TreeNode root){
if(root == null) return;
minGet(root.left);
if(temp != null) result = Math.min(result, Math.abs(root.val - temp.val));
temp = root;//用来记录上一个节点
minGet(root.right);
}
}
方法二:迭代法(中序遍历)
class Solution {
//中序遍历
public int getMinimumDifference(TreeNode root) {
if(root == null) return 0;
int result = Integer.MAX_VALUE;
Stack<TreeNode> st = new Stack<>();
TreeNode cur = root;
TreeNode pre = null;//用来保存上一个节点
while(cur != null || !st.isEmpty()){
if(cur != null){
st.push(cur);//将访问的节点放进栈里面
cur = cur.left;//一直递归到最左
}else{
cur = st.pop();
if(pre != null) result = Math.min(result, Math.abs(cur.val - pre.val));//中
pre = cur;
cur = cur.right;//右
}
}
return result;
}
}
17.二叉搜索树中的众数
递归法(利用中序遍历)
class Solution {
List<Integer> result = new ArrayList<>();
TreeNode pre;//记录上一个节点
int maxcount;//记录最大数量
int count;//记录每个数的数量
public int[] findMode(TreeNode root) {
maxcount = 0;
count = 0;
pre = null;//给其赋初始值
findMode1(root);
int[] res = new int[result.size()];//因为返回类型是int的数组
for(int i = 0; i < result.size(); i ++){
res[i] = result.get(i);//注意这里get函数的用法,里面要有i
}
return res;
}
public void findMode1(TreeNode root){
//根据二叉搜索树的特点(中序遍历)
if(root == null) return;
findMode1(root.left);//左
if(pre == null || pre.val != root.val){
count = 1;//如果和上一个数不一样,就重新赋值为1(包括pre结点为空的情况)
}else{
count ++;//如果一样,数量就加1
}
if(count > maxcount){
maxcount = count;//说明更可能的众数出现了,要重新赋最大值
result.clear();//把结果清空
result.add(root.val);//把最新可能的众数加进去
}else if(count == maxcount){
result.add(root.val);//如果数量相同,就说明可能有多个众数,只需要把当前的数加入结果即可
}
pre = root;//保存上一个结点
findMode1(root.right);//右
}
}
18.二叉树、二叉搜索树的最近公共祖先
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;//递归结束的条件
//后序遍历
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left == null && right == null) return null;//左右都为空
else if(left != null && right == null) return left;//找到一个(左边)
else if(right != null && left == null) return right;//找到一个(右边)
else return root;//左右都找到了
}
}
235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
方法一:递归法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val < q.val && root.val < p.val) return lowestCommonAncestor(root.right, p, q);//比qp都小,在右边
else if(root.val > q.val && root.val > p.val) return lowestCommonAncestor(root.left, p, q);//比qp都大,在左边
else return root;//如果pq在root的一左一右,那么root一定是最近公共祖先
}
}
方法二:迭代法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(true){
if(root.val < p.val && root.val < q.val) root = root.right;
else if(root.val > p.val && root.val > q.val) root = root.left;
else break;
}
return root;
}
}
19.二叉搜索树的基本操作(插入、删除)
701. 二叉搜索树中的插入操作 - 力扣(LeetCode)
方法一:递归法
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
//如果节点为空,就说明找到了合适的位置,创建新的结点赋值直接返回
if(root == null) return new TreeNode(val);
//向左向右寻找合适的位置
if(root.val < val) root.right = insertIntoBST(root.right, val);
else if(root.val > val) root.left = insertIntoBST(root.left, val);
return root;
}
}
方法二:迭代法
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) return new TreeNode(val);
TreeNode pre = root;//保存父节点,才能找到结点,进行插入的操作
TreeNode cur = root;
while(cur != null){
pre = cur;
if(cur.val > val) cur = cur.left;
else if(cur.val < val) cur = cur.right;
}
if(pre.val > val) pre.left = new TreeNode(val);
else if (pre.val < val) pre.right = new TreeNode(val);
return root;
}
}
450. 删除二叉搜索树中的节点 - 力扣(LeetCode)
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return root;
if(root.val == key)//找到删除点
{
if(root.left == null) return root.right;//包含第二和第三种情况
else if(root.right == null) return root.left;//第四种情况
else{//第五种情况(删除点左右都不为空)
TreeNode cur = root.right;//把删除点的右子节点存下来
while(cur.left != null) cur = cur.left;//递归找到右子节点的最左的那个点(即最小的点)
cur.left = root.left;//把删除点的左孩子结点放进右子节点的最左的那个点
return root.right;//返回右子节点
}
}
if(root.val > key) root.left = deleteNode(root.left, key);//递归查找删除点
if(root.val < key) root.right = deleteNode(root.right, key);
return root;
}
}
20.修剪二叉搜索树
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) return root;//返回空值
if(root.val > high) return trimBST(root.left, low, high);//砍右大只
if(root.val < low) return trimBST(root.right, low, high);//砍左大只
//root在[low, high]范围内
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}
21.将有序数组转换为(高度平衡)二叉搜索树
108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
方法一:左闭右闭
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return transform(nums, 0, nums.length - 1);
}
public TreeNode transform(int[] nums, int left, int right){
//坚持左闭右闭原则
if(left > right) return null;//当数组为空时,返回null
//求出中心值
int mid = left + ((right - left) >> 1);
TreeNode root = new TreeNode(nums[mid]);//建立根节点
root.left = transform(nums, left, mid - 1);//循环建立左右节点
root.right = transform(nums, mid + 1, right);
return root;
}
}
方法二:左闭右开
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return transform(nums, 0, nums.length);
}
public TreeNode transform(int[] nums, int left, int right){
//全部坚持左闭右开原则
if(left >= right) return null;
if(right - left == 1) return new TreeNode(nums[left]);
int mid = left + ((right - left) >> 1);
TreeNode root = new TreeNode(nums[mid]);
root.left = transform(nums, left, mid);
root.right = transform(nums, mid + 1, right);
return root;
}
}
22.把二叉搜索树转换为累加树
538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)
class Solution {
int sum;//定义变量,让他在函数里面可以用
public TreeNode convertBST(TreeNode root) {
sum = 0;
adding(root);
return root;
}
public void adding(TreeNode root){
if(root == null) return;
//反向中序遍历(右中左)
adding(root.right);
sum += root.val;//把前面的值相加,并用sum保存下来
root.val = sum;//把sum的值赋给结点的值
adding(root.left);
}
}