C#二叉树力扣题逐行详解 初学者必看(题目会更新)

树分为两种遍历方式,分别是深度优先遍历和广度优先遍历。这里我们先看关于深度优先的三道题,分别是前序(中左右)中序(左中右)后序(左右中),二叉树的定义和链表类似,多写,刚开始记不住就背下来。
144.二叉树的前序遍历
在这里插入图片描述

分析:前序遍历,使用栈和数组来实现
(1)前序遍历也就是中左右,先放中间节点,再放左右子节点
(2)栈是先进后出,所以放入元素的顺序应该是先右再左,这样出来的元素才能是正常的
(3)流程:栈中右root结点,进入循环后弹出,然后分别加入root的右节点和左节点(右节点先加入),再下次循环中先将左节点弹出,随后再判断是否需要加入左节点的左右节点。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *	   //可以看一下树的定义
 *	   //值 左右节点 构造函数
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public IList<int> PreorderTraversal(TreeNode root) {
    	//声明数组和栈
        Stack<TreeNode> st1 = new Stack<TreeNode>();
        List<int> list1 = new List<int>();
        //当根节点为空 就返回空数组
        if(root == null)return list1;
        //首先我们需要将根节点放入栈中
        st1.Push(root);
        //当栈中元素不为空
        while(st1.Count != 0)
        {
        	//定义一个临时变量去接收弹出的元素
            var temp = st1.Pop();
            //在定义好的数组中添加该元素
            list1.Add(temp.val);
            //当右边不为空的时候 我们放入右边的元素
            if(temp.right != null)
            {
                st1.Push(temp.right);
            }
            //当左边不为空的时候 我们放入左边的元素
            if(temp.left != null)
            {
                st1.Push(temp.left);
            }
        }
        return list1;
    }
}

递归写法
分析:(1)List声明记得要写在外部,因为是递归,不能重复创建List
(2)递归三要素:递归参数,结束条件,递归逻辑
(3)无限搜索左子节点 直到为空返回,无限搜索右子节点 知道为空返回,搜索一次往List添加一次不为空的值,最终返回到根节点的左右节点,返回List

public class Solution {
        List<int> list1 = new List<int>();
    public IList<int> PreorderTraversal(TreeNode root) {
        if(root == null) return list1;
        list1.Add(root.val);
        PreorderTraversal(root.left);
        PreorderTraversal(root.right);
        return list1;
    }
}

94.二叉树的中序遍历
在这里插入图片描述
分析:中序遍历(左中右)这里使用递归的方式来实现,为什么和前序遍历的写法不太一样?因为前序遍历先处理根节点,而中序需要先处理左节点,递归我觉得更好实现。下题后序遍历会发现和前序很类似。
(1)递归就是可以不断地访问左节点,直到它为空在返回上一层,这样我们就实现了中序遍历
(2)(结合如下图和代码 代入思考)流程:根据root节点,先判断左节点是否为空,不为空就递归调用,直到传入节点的左节点(红left)为空,就添加传入的节点(红left),随后判断右节点是否为空,不为空就递归调用。之后返回上一层,那刚才传入的节点(红left)就是上一层的左节点,所以添加上一层的节点,之后在判断右节点,然后再返回上一层,直到最后添加root根节点就算结束。
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
	//list需要声明在外部 因为这里是递归调用这个方法 不能重复声明list
    List<int> list1 = new List<int>();
    public IList<int> InorderTraversal(TreeNode root) {
    	if(root == null)
            return list1;
        if(root != null)
        {
        	//判断左节点是否为空
            if(root.left!=null)
            	//传入该节点的左节点
            	//不为空就开始递归调用 直到为空 再往下执行
                InorderTraversal(root.left);
            //传入的节点的左节点为空 就向list中添加传入的节点
            list1.Add(root.val);
            //判断右节点是否为空
            if(root.right!=null)
            	//不为空就添加右节点
                InorderTraversal(root.right);        
        }
        return list1;
        }
    }

分析:前序(中左右)和后序(左右中)我推荐都使用迭代法,也就是第一题中的写法。
(1)中左右其实可以调换一下左右节点的判断顺序,就可以变成中右左,再将数组整个翻转,就可以变成左右中,也就是后序遍历
中左右-----中右左-----左右中
(2)那么只要写出前序前序遍历,不难写出后序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public IList<int> PostorderTraversal(TreeNode root) {
        Stack<TreeNode> st1 = new Stack<TreeNode>();
        List<int> list1 = new List<int>();
        if(root == null)
        	return list1;
        st1.Push(root);
        while(st1.Count > 0)
        {
            var temp = st1.Pop();
            list1.Add(temp.val);
            //这里调换出栈的左右顺序 
             if(temp.left != null)
                st1.Push(temp.left);
            if(temp.right != null)
                st1.Push(temp.right);
        }
        //list翻转即可
        list1.Reverse(0,list1.Count);
        return list1;
    } 
}

接下来看广度优先遍历题目,也就是层序遍历
102.二叉树的层序遍历
在这里插入图片描述
分析:首先层序遍历要求一层一层的结果,所以返回的数组有多个。这里还需要使用队列,因为队列先进先出,我们按层搜索元素使用队列更适合。
(1)有一个要点就是需要一个临时变量记录一下队列中元素的数量,这样我们才能在队列中判断,一层的元素是否都出队完成了,才能判断下一层的元素。
(2)流程:将元素不断地放入队列,同时记录一下该层元素的数量,出队后再入队它的左右节点,通过记录数量就可以控制for循环,然后将各层的数组添加到总数组中即可。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public IList<IList<int>> LevelOrder(TreeNode root) {
    	//根据返回值要求声明对应的变量
        IList<IList<int>> list1 = new List<IList<int>>();
        Queue<TreeNode> queue1 = new Queue<TreeNode>();
        if(root == null) return list1;
        //先将根节点入队
        queue1.Enqueue(root);
        //记得写while 不是if
        while(queue1.Count != 0)
        {
        	//这个是很重要的一点 也就是记录这层队列中元素的数量
        	//
            int count = queue1.Count;
            List<int> list2 = new List<int>();
            //这样就可以根据这层元素的数量进行for循环
            for(int i = 0; i < count; i++)
            {
            	//将队列中的元素出队
                TreeNode temp = queue1.Dequeue();
                //添加到新数组中
                list2.Add(temp.val);
                //之后判断它的左右节点 分别加入到队列
                 if(temp.left != null)
                {
                    queue1.Enqueue(temp.left);
                }
                if(temp.right != null)
                {
                    queue1.Enqueue(temp.right);
                }
            }
            //最后将每一层的数组都添加到总数组中
            list1.Add(list2);
        }
        return list1;
    }
}

还有几个非常类似的题目,只需要明白上述题目,稍作调整即可,一起来看一下
在这里插入图片描述
它要从下往上返回值,其实就是翻转总数组即可。

list1.Reverse();

在这里插入图片描述
它要求返回一层中最后一个值,每层的数量我们记录过了,在for循环中,当i等于最后一个值的时候,我们添加到数组即可。

if(i == count -1)
   result.Add(temp.val);

在这里插入图片描述
它要求返回一层的平均值,那么就可以通过一个临时变量,当队列元素出队的时候,我们就把它的值加到临时变量中(我这里只截了需要使用sum的地方)

while(queue.Count != 0)
        {
            int size = queue.Count;
            double sum = 0;
            for(int i = 0;i < size; i++)
            {
                TreeNode temp = queue.Dequeue();
                sum += temp.val;
                if(temp.left != null)
                    queue.Enqueue(temp.left);
                if(temp.right != null)
                    queue.Enqueue(temp.right);
            }
            sum /= size;
            list1.Add(sum);
        }

在这里插入图片描述
看到这种题目第一反应就是需要一个临时变量记录值

while(queue.Count != 0)
        {
            int size = queue.Count;
       //比较 就需要有参照物对吧 所以我们以队列的头节点作为参照物即可
            int head = queue.Peek().val;
            for(int i = 0;i < size; i++)
            {
                TreeNode temp = queue.Dequeue();
                //用出队元素和队列头节点进行比较 最大的就记录下来 
                if(head <= temp.val)
                    head = temp.val; 
                if(temp.left != null)
                    queue.Enqueue(temp.left);
                if(temp.right != null)
                    queue.Enqueue(temp.right);
            }
            //只添加大的即可
            list1.Add(head);
        }

在这里插入图片描述
分析:这个题最后要求用’#‘连接标志着每一层的结束,应该指针代表的就是’#',那本题其实核心就是i等于最后一个元素或者队列长度为0的时候,那就直接让出队的元素指向null;其余情况都直接让它指向队列的头部(也就是下一个元素)因为一个元素出队,那么下一个元素就成为了队首(这里我只截了核心代码)

        while(queue.Count > 0)
        {
            int size = queue.Count;
            for(int i = 0;i < size; i++)
            {
                Node temp = queue.Dequeue();
                if(size == 0 || i == size - 1)
                {
                    temp.next = null;
                }
                else 
                {
                    temp.next = queue.Peek();
                }
                if(temp.left != null)
                    queue.Enqueue(temp.left);
                if(temp.right != null)
                    queue.Enqueue(temp.right);
            }
        }

这道题建议大家用ACM模式完成
226.翻转二叉树
在这里插入图片描述
分析:翻转二叉树,采用的是递归,将他的所有子节点都进行翻转,就实现了树的翻转

public class 二叉树 : MonoBehaviour {

	void Start () {
		//二叉树的实例化
		TreeNode t1 = new TreeNode(4);
        TreeNode t2 = new TreeNode(2);
        TreeNode t3 = new TreeNode(7);
        TreeNode t4 = new TreeNode(1);
        TreeNode t5 = new TreeNode(3);
        TreeNode t6 = new TreeNode(6);
        TreeNode t7 = new TreeNode(9);
        //子节点声明
		t1.left = t2;
		t1.right = t3;
		t2.left = t4;
		t2.right = t5;
		t3.left = t6;
		t3.right = t7;
		//翻转并打印
		ReverseTree(t1);
		Print(t1);
    }
	
	public class TreeNode
	{
		public int val;
		public TreeNode left;
		public TreeNode right;
		public TreeNode(int val)
		{
			this.val = val;
		}
	}
	//翻转方法 先递归左子节点 再递归右子节点 然后翻转即可
	public TreeNode ReverseTree(TreeNode root)
	{
		if(root == null)
		{
			return null;
		}
        ReverseTree(root.left);
        ReverseTree(root.right);
		var temp = root.left;
		root.left = root.right;
		root.right = temp;
		return root;
	}
	//打印方法
	//有点类似层序遍历写法 就是队列弹出元素后加入左右子节点即可
	public void Print(TreeNode root)
	{
		Queue<TreeNode> queue = new Queue<TreeNode>();
		queue.Enqueue(root);
		while(queue.Count > 0)
		{
			var temp = queue.Dequeue();
			Debug.Log(temp.val);
			if(temp.left != null)
			{
				queue.Enqueue(temp.left);
			}
            if (temp.right != null)
            {
                queue.Enqueue(temp.right);
            }
        }
	}
}

以下两题可以使用递归实现
589.N叉树的前序遍历
在这里插入图片描述
分析:这道题类似前序遍历,要求按前序(中左右)的方式返回值

/*
// Definition for a Node.
public class Node {
    public int val;
    public IList<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,IList<Node> _children) {
        val = _val;
        children = _children;
    }
}
*/

public class Solution {
	//这里是需要两个方法的 为什么一个方法不能完成呢?
	//因为递归我们需要输入参数 而子节点都是List 所以一个方法返回节点 输入却是列表
    public IList<int> Preorder(Node root) {
        var list1 = new List<int>();
        if(root == null) return list1;
        //先加入根节点
        list1.Add(root.val);
        //关键点就是传入List 因为从始至终我们只需要一个List
        Preorder(list1,root);
        return list1;
    }
    public void Preorder(IList<int> list1, Node root)
    {
    	//遍历所有节点 递归调用并向List中添加元素 直到传入的root为空就会返回上一层
        foreach(var v in root.children)
        {
            list1.Add(v.val);
            Preorder(list1,v);
        }
    }
}

590.N叉树的后序遍历
在这里插入图片描述
分析:那前面已经讲过前序遍历—后序遍历,就是中左右—中右左—左右中,所以这里也是一样的

public class Solution {
    public IList<int> Postorder(Node root) {
        var list1 = new List<int>();
        if(root == null) return list1;
        list1.Add(root.val);
        Postorder(list1,root);
        //翻转:中右左---左右中
        list1.Reverse(0,list1.Count);
        return list1;
    }
    public void Postorder(IList<int> list1, Node root)
    {
    	//foreach是只能从前往后进行遍历 所以使用for循环即可
    	//就从中左右 变成了 中右左
        for(int i = root.children.Count - 1; i >= 0; i--)
        {
            list1.Add(root.children[i].val);
            Postorder(list1,root.children[i]);
        }
    }
}

104.二叉树的最大深度
在这里插入图片描述
分析:首先要分清楚高度和深度的区别,建议去看一下代码随想录的讲解
(1)高度(后序遍历):从下往上去计数,也就是从子节点计数为1,父节点为2,再往上为3…
(2)深度(前序遍历):从上往下去计数,也就是从根节点计数为1,子节点为2,再往下为3…
本题其实使用的是后序遍历

public class Solution {
    public int MaxDepth(TreeNode root)
    {
    	//递归到子节点开始计数 也就是当一个节点的子节点等于0 那就返回0到这个节点
    	//然后这个节点再往上返回的时候 要和另一个节点比较得最大值后再+1
    	//为什么要+1?比如你住在5楼,那你距离1楼有4层,+1算上自己才是你的高度
        if(root == null) return 0;
        int leftDepth = MaxDepth(root.left);
        int rightDepth = MaxDepth(root.right);
        return Math.Max(leftDepth, rightDepth) + 1;
        /* 也可以精简为如下代码
        if(root == null) return 0;
        return Math.Max(MaxDepth(root.left), MaxDepth(root.right)) + 1;
        */
    }
}

101.对称二叉树
在这里插入图片描述
分析:要求一棵树是对称的,这里使用递归来实现,那就要考虑递归三要素
(1)递归参数:那比较的目的是对称,所以传入的节点自然是左右节点
(2)递归逻辑:就是左子树的左节点和右子树的右节点进行判断。还需要判断什么情况下就是false,就是不对称。
·左节点为空,右节点不为空,false
·左节点不为空,右节点为空,false
·左节点值 不等于 右节点值 ,false
·左节点为空,右节点也为空,true
(3)结束条件:当最后返回值都为true

public class Solution {
    public bool IsSymmetric(TreeNode root) {
        return Compare(root.left,root.right);
    }
    //因为要递归 需要另写一个方法 传入左节点和右节点
    public bool Compare(TreeNode left,TreeNode right)
    {
    	//上述说过的四种情况
        if(left == null && right != null)return false;
        else if(left != null && right == null)return false;
        else if(left == null && right == null)return true;
        else if(left.val != right.val)return false;
        //这里可以做简写 这样更好理解而已
        //就是比较左子树的左节点和右子树的右节点
        var temp = Compare(left.left,right.right);
        //一样
        var temp2 = Compare(left.right,right.left);
        //返回的值都为true才能是对称的
        return temp && temp2;
    }
}

111.二叉树的最小深度
在这里插入图片描述
分析:这道题和最大深度有点出入,关键就是多考虑两种情况。叶子节点就是左右节点都为空的节点(图中9,15,7都是,本题要求返回最小值)
(1)解题还是从下往上依次返回节点,每层+1
(2)我们最终返回值肯定是取最小值,那有一个问题,例如下图中2的左子节点为null,右子节点不为null,那很明显2并不是叶子节点,但是返回的时候最小值一定会被这个值影响,所以我们要考虑两种情况:就是当左子节点为null,右子节点不为空的时候,应该用右子节点的最小高度 + 1;另一种就是就是当右子节点为null,左子节点不为空的时候,应该用左子节点的最小高度 + 1。
(3)有点懵对吧,我们结合代码和图一起看一下:传入根节点2,当left = null时,最终返回值为1;right则一直往下递归,直到传入节点6,那此时6的左右子节点都为null,(返回值)0+1,则6这层的返回值是1。往回递归,传入5这里值就是2,传入4这里值就是3,传入3这里值就是4,此时的right就是4,也就是真正的叶子节点的高度。那最后取最小值 Math.Min(left,right) + 1,如果不处理根节点的左子节点,此时返回的最小值一定是这个为null节点的值,所以当左子节点为null,右子节点不为空返回的最小值应该是 right + 1,因为左子节点 = null 已经报废了,可以这样理解,它影响到了我们取最小值,应该以同层的右子节点的值为准。右为空,左不为空,同理。
在这里插入图片描述

public class Solution {
    public int MinDepth(TreeNode root) {
        return FindMin(root);
    }
    public int FindMin(TreeNode root)
    {
        if(root == null) return 0;
        int left = FindMin(root.left);
        int right = FindMin(root.right);
        if(root.left == null && root.right != null) return right + 1;
        if(root.right == null && root.left != null) return left + 1;
        return Math.Min(left,right) + 1;
    }
}

222.完全二叉树的节点个数
在这里插入图片描述
分析:就是得出节点个数,只要能遍历所有节点的方法都ok,这里用了递归和层序遍历

//递归
public int CountNodes(TreeNode root) {
        if(root == null) return 0;
        return CountNodes(root.left) + CountNodes(root.right) + 1;
    }
//层序遍历
public int CountNodes(TreeNode root) {
        if(root == null) return 0;
        int count = 1;
        var queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        while(queue.Count != 0)
        {
            var temp = queue.Dequeue();
            if(temp.left != null)
            {
                queue.Enqueue(temp.left);
                ++count;
            }
            if(temp.right != null)
            {
                queue.Enqueue(temp.right);
                ++count;
            }
        }
        return count;
    }

110.平衡二叉树
在这里插入图片描述
分析:平衡二叉树就是左右子树的高度相差大于1。本题使用递归,具体看代码。

public class Solution {
    public bool IsBalanced(TreeNode root) {
    	//root为空返回true是题目要求
        if(root == null) return true;
        //我们设定当左右子树高度差大于1时 就返回-1 那-1说明就不是平衡二叉树
        return GetHight(root) == -1 ? false : true;
    }
    public int GetHight(TreeNode root)
    {
        if(root == null) return 0; 
        //左子树的高度
        int leftH = GetHight(root.left);
        //默认当它等于-1 就返回-1 不是平衡二叉树
        //下面的判断条件我们来写它什么时候等于-1
        if(leftH == -1) return -1;
        //右子树高度
        int rightH = GetHight(root.right);
        //同理
        if(rightH == -1) return -1;
        //那就是当左右子树的高度差绝对值大于1时 说明不是平衡二叉树
        //返回-1
        if(Math.Abs(leftH - rightH) > 1)return -1;
        //否则就说明都符合平衡二叉树 那就返回每层的最大高度
        return Math.Max(leftH,rightH) + 1;
    }
}

257.二叉树的所有路径
在这里插入图片描述
分析:前序遍历节点,当遇到叶子节点的时候向IList中添加

public class Solution {
    public IList<string> BinaryTreePaths(TreeNode root) {
    	//IList是返回值 List用来存放值
        IList<string> result = new List<string>();
        List<int> list = new List<int>();
        //所以都要传过去
        Path(root, list, result);
        return result;
    }
    public void Path(TreeNode root, List<int> list, IList<string> result) {
    	//节点为空就返回
        if(root == null) return;
        //每次遍历的元素不为空都添加到List中
        list.Add(root.val);
        //遇到叶子节点
        //先将List中已有的节点拼接箭头 然后添加到IList中
        if(root.left == null && root.right == null) {
            result.Add(string.Join("->", list));
        }
        else {
        //没有遇到叶子节点
        //递归调用
            Path(root.left, list, result);
            Path(root.right, list, result);
        }
        //那遇到叶子节点向IList添加完结果后 最后执行到这一行 往回return 依次清除最后一个元素
        list.RemoveAt(list.Count - 1);
    }
}

404.左叶子之和
在这里插入图片描述
分析:题目要求返回左子叶之和,注意是当这个节点的左右节点都为空的时候,才返回哦。那我们判断:当一个节点的左节点不为空 同时 节点的左节点的左右节点都为空,那说明就是我们要的节点(有点绕 直接看代码)

public class Solution 
{
	//记得sum写在外面 因为GetSum会递归调用
    int sum = 0;
    public int SumOfLeftLeaves(TreeNode root) 
    {
        return GetSum(root);
    }
    public int GetSum(TreeNode root)
    {
        if(root == null)return 0;
        //传入节点的左节点不为空 传入节点的左节点的左节点 和 传入节点的左节点的右节点 为空
        //那就说明该节点的值是我们需要的 就加到sum中
        //注意这里看清楚 容易写混
        if(root.left != null && root.left.left == null && root.left.right == null)
        {
            sum += root.left.val;
        }
        GetSum(root.left);
        GetSum(root.right);
        return sum;
    }
}

513.找树左下角的值
在这里插入图片描述
分析:这道题目要求我们找最底层 最左边的值,那自然就能联想到需要全局变量去记录最大深度和最左侧的值,我分别用递归和层序遍历的方式实现
递归(1)使用前序遍历,求叶子节点(节点的左节点为空,节点的右节点为空),同时记录最大深度,那谁的深度值最大,就以谁的叶子节点为准
(2)流程:每次递归都会对深度+1,那当找到叶子节点,同时深度是大于全局变量的话,说明这个节点深度最大,那就返回该值
迭代(1)最常写的层序遍历的方式,多加一个全局变量,记录每次最左侧的值,如果还有下一层,那就会去把最左侧的值更新掉

//递归
public class Solution {
	//记录最大深度 对比使用的 因为maxDep也不可能小于0
	//如果最大深度为负数 说明没有符合的节点
    public int maxDep = -1;
    //记录值
    public int result = 0;
    public int FindBottomLeftValue(TreeNode root) {
    	//传入根节点和0 
        FindDeep(root,0);
        return result;
    }
    public void FindDeep(TreeNode root,int depth)
    {
    	//判断叶子节点 
    	//如果一个值深度最大 但它是右节点 那也算符合题意
    	//因为即使是右节点 但最大深度只有它一个值 那它就是最左侧的值
        if(root.left == null && root.right == null)
        {
        	//深度大于已经记录的深度
            if(depth > maxDep)
            {
            	//更新深度 更新值
                maxDep = depth;
                result = root.val;
            }
        }
        //递归要对深度+1
        if(root.left != null)
        {
            FindDeep(root.left,depth + 1);
        }
        if(root.right != null)
        {
            FindDeep(root.right,depth + 1);
        }
    }
}
//迭代
public class Solution {
    public int FindBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        int result = 0;
        while(queue.Count != 0)
        {
            int count = queue.Count;
            for(int i = 0; i < count; i++)
            {
                var temp = queue.Dequeue();
                if(i == 0)
                {
                    result = temp.val;
                }
                if(temp.left != null)
                {
                    queue.Enqueue(temp.left);
                }
                if(temp.right != null)
                {
                    queue.Enqueue(temp.right);
                }
            }
        }
        return result;
    }
}

112.路径总和
在这里插入图片描述
分析:题目要求找到一个路径,相加起来等于目标值,那这里我们使用递归解决,核心就是每次把节点的值减去,在找到根节点后,值为0说明符合题意。

public class Solution {
    public bool HasPathSum(TreeNode root, int targetSum) {
    	//注意题目要求返回的是bool值
        if(root == null) return false;
        //一个临时变量 每当传入一个节点 就减去一次
        int count = targetSum - root.val;
        //找到叶子节点
        if(root.left == null && root.right == null)
        {
        	//最后传入叶子节点 变量等于0 符合题意
            return count == 0;
        }
        //递归调用传入临时变量 也就是传入一个节点 目标值减去一个节点的值 这样也更好理解
        var left = HasPathSum(root.left,count);
        var right = HasPathSum(root.right,count);
        //左右都递归 只要满足一个就是符合题意 所以用||
        return left || right;
    }
}

106.从中序与后序遍历序列构造二叉树(该题还不够理解 请略过)
在这里插入图片描述
分析:本题的思路就是将一个数组分别拆分为左右两个数组,代表除了头节点外的左右两边数组。(1)后序遍历是左右中,所以后序数组的最后一个元素就是头节点,那都是以左开始,所以左数组也很容易就确定了
(2)分别对中序数组和后序数组进行切割,分成左右两个数组,就按照(1)的规律递归调用切割数组
(3)代码中有两个小数点 我也不知道是什么写法,搜了半天也没有,我也是看到别人这样写,默认他就是for循环吧,但是声明数组长度为0我很费劲,如果有懂的大神可以解答一下

public class Solution {
    public TreeNode BuildTree(int[] inorder, int[] postorder) {
        if(inorder.Length == 0 && postorder.Length == 0) return null;
        //先找头节点 就是后序数组的最后一个元素
        int headVal = postorder[postorder.Length - 1];
        TreeNode newTree = new TreeNode(headVal);
        //中序左右数组
        int[] inorderLeft = new int[0];int[] inorderRight  = new int[0];
        //后序左右数组
        int[] postorderLeft  = new int[0];int[] postorderRight = new int[0];
        //索引位 标识从第几位开始切割
        //那中序数组(左中右)在找到中元素时 就是切割数组的地方
        int tempIndex = 0;
        for(int i = 0; i < inorder.Length; i++)
        {
            if(inorder[i] == headVal)
            {
                tempIndex = i;
                break;
            }
        }
        //当索引不为0 说明有左子树
        if (tempIndex != 0)
        {
        	//给数组赋值
        	//中序左数组
            inorderLeft = inorder[0..tempIndex];
            //后序左数组
            postorderLeft = postorder[0..tempIndex];
        }
        if (tempIndex != inorder.Length - 1)
        {
        	//中序右数组
            inorderRight = inorder[(tempIndex + 1)..inorder.Length];
            //后序右数组
            postorderRight = postorder[tempIndex..(postorder.Length - 1)];
        }
        newTree.left = BuildTree(inorderLeft,postorderLeft);
        newTree.right = BuildTree(inorderRight,postorderRight);
        return newTree;
    }
}

654.最大二叉树
在这里插入图片描述

在这里插入图片描述

分析:和上一题类似,就是分割成两个数组,递归调用即可

public class Solution {
    public TreeNode ConstructMaximumBinaryTree(int[] nums) {
    	//使用递归就需要有终止条件
        if(nums == null || nums.Length == 0) return null;
        //找到最大值
        int maxIndex = 0;
        int maxValue = 0;
        for(int i = 0; i < nums.Length; i++)
        {
            if(nums[i] > maxValue)
            {
                maxValue = nums[i];
                maxIndex = i;
            }
        }
        //创建节点
        TreeNode root = new TreeNode(nums[maxIndex]);
        //递归调用
        root.left = ConstructMaximumBinaryTree(CopyArray(nums,0,maxIndex - 1));
        root.right = ConstructMaximumBinaryTree(CopyArray(nums,maxIndex + 1,nums.Length - 1));
        return root;
   }
   public int[] CopyArray(int[] nums,int left,int right)
   {
   		//递归就要有终止条件
        if(left > right) return null;
   		//通过创建新数组并返回
        int length = right - left + 1;
        int[] newNums = new int[length];
        for(int i = left; i <= right; i++)
        {
        	//i-left 是因为新数组的索引都是从0开始的 right不需要减去 因为新数组长度已经定好了
            newNums[i - left] = nums[i];
        }
        return newNums;
   }
}

617.合并二叉树
在这里插入图片描述
分析:创建一个新节点,然后将这两个树的值递归合并给新节点就好了

public class Solution {
    public TreeNode MergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null)return root2;
        if(root2 == null)return root1;
        TreeNode root3 = new TreeNode();
        root3.val = root1.val + root2.val;
        root3.left = MergeTrees(root1.left, root2.left);
        root3.right = MergeTrees(root1.right, root2.right);
        return root3;
    }
}

700.二叉搜索树中的搜索
在这里插入图片描述
分析:二叉搜索树就是 左子树的值都会小于根节点 右子树的值都大于根节点,本题使用递归或者迭代都可以实现,迭代写起来也很简单,不需要使用栈和队列,因为二叉搜索树是已经排序好的,我们直接迭代就好了。

public class Solution {
//递归
public class Solution {
    public TreeNode SearchBST(TreeNode root, int val)
{
    if (root == null || root.val == val) return root;
    //搜索左右两边的时候 记得return
    if (root.val > val) return SearchBST(root.left, val);
    if (root.val < val) return SearchBST(root.right, val);
    //如果都没找到 那就说明没有目标节点 
    return null;
}
}
//迭代
    public TreeNode SearchBST(TreeNode root, int val) {
        while(root != null)
        {
            if(root.val == val) return root;
            else if(root.val < val) root = root.right;
            else if(root.val > val) root = root.left;
        }
        return null;
    }
}

92.验证二叉搜索树
在这里插入图片描述
分析:题目要求左子树的值全小于根节点,右子树的值全大于根节点,那就可以使用中序遍历的方式,将所有的值放到List中,如果List是有序的,说明是二叉搜索树。

public class Solution {
    List<int> list = new List<int>();
    public bool IsValidBST(TreeNode root)
    {
        Find(root);
        //这里就是判断List是否有序
        for(int i = 1;i < list.Count; i++)
        {
            if(list[i] > list[i - 1])
            {
                continue;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    //中序遍历 将所有的值都放入List中即可
    public void Find(TreeNode root)
    {
        if(root == null) return;
        if(root.left != null)
            Find(root.left);
        list.Add(root.val);
        if(root.right != null)
            Find(root.right);
    }
}

530.二叉搜索树的最小绝对差
在这里插入图片描述
分析:和上题类似,本题还是根据二叉搜索树的特性,通过中序遍历将所有的元素放入队列中就是有序的,再通过两两比较,取最小的差值返回即可

public class Solution {
    List<int> list1 = new List<int>();
    public int GetMinimumDifference(TreeNode root) {
    	//temp采用int的最大值 方便后续进行比较
        int temp = int.MaxValue;
        Find(root);
        for(int i = 1; i < list1.Count; i++)
        {
        	//最大值和很多差值比较 选择一个最小的
            temp = Math.Min(temp,list1[i] - list1[i - 1]);
        }
        return temp;
    }
    public void Find(TreeNode root)
    {
    	//中序遍历放入List中
        if(root == null) return;
        if(root != null)
        {
            Find(root.left);
        }
        list1.Add(root.val);
        if(root != null)
        {
            Find(root.right);
        }
    } 
}
  • 36
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
二叉树的层序遍历是一种广度优先搜索的算法,它按照层次逐层地遍历二叉树的节点。可以通过使用一个队列来实现层序遍历。首先将根节点入队,然后循环执行以下步骤,直到队列为空: 1. 弹出队首节点,并将其值加入结果数组。 2. 如果该节点有左孩子,则将左孩子入队。 3. 如果该节点有右孩子,则将右孩子入队。 4. 重复以上步骤直到队列为空。 以下是一个用C++实现的二叉树层序遍历的示例代码: ```cpp class Solution { public: vector<double> averageOfLevels(TreeNode* root) { vector<double> result; // 存放每层的平均值 queue<TreeNode*> q; // 队列 if (root == nullptr) { return result; } q.push(root); // 根节点入队 while (!q.empty()) { double sum = 0; // 当前层节点值的和 int size = q.size(); // 当前层节点数量 for (int i = 0; i < size; i++) { TreeNode* node = q.front(); q.pop(); sum += node->val; if (node->left) { q.push(node->left); } if (node->right) { q.push(node->right); } } result.push_back(sum / size); // 计算平均值并加入结果数组 } return result; } }; ``` 以上代码通过遍历每一层的节点,并计算该层节点值的和和数量,然后将平均值加入结果数组。最终返回结果数组即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [力扣二叉树的层序遍历](https://blog.csdn.net/m0_58367586/article/details/124107118)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值