leetcode 经典二叉树算法题目(思路、方法、code)

leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code) leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code) BFS和DFS的经典应用就是在树和图中的遍历。 地图的搜索问题通常都可以用BFS和DFS解决,下面题目非常典型,并且很多题目类似,自己如果能够独立完成基本就掌握了BFS和DFS以及地图的遍历问题。 文章目录leetcode 经典宽搜BFS深搜DFS题目(思路、方法、code)[200. 岛屿数量](https://leetcode-cn.com/problems/number-of-islands/)[127. 单词接龙](https: 阅读详情

leetcode 经典二叉树算法题目(思路、方法、code)

二叉树相关题目,主要就是要搞定二叉树的多种遍历方式,包括先序遍历,中序遍历,后序遍历,层次遍历,DFS遍历。掌握了所有的遍历方法,二叉树的题目基本就化简为一些简单问题去解决。
二叉树由于其良好的结构,很多题目都可以化为递归去解决。


二叉树的常用结构体定义:

 struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
226. 翻转二叉树

翻转一棵二叉树。

示例:
输入:
         4
       /   \
      2     7
     / \   / \
    1   3 6   9
输出:
   	    4
  	  /   \
 	 7     2
 	/ \   / \
	9   6 3   1

分析:翻转二叉树是非常经典的一个问题。

方法一:递归

  • 如果一个树是空的,则翻转的结果仍为空
  • 如果一个树非空,则翻转的结果应该为,翻转后的树的左子树应该是原来右子树经过翻转得到的,翻转后的树的右子树应该是右原来的左子树翻转得到的
  • 根据该递归规则进行递归即可
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL) return NULL;
        TreeNode* temp=root->left; //注意需要一个中间变量
        root->left=invertTree(root->right);//这里左子树将发生变化,故之前需要中间变量保存下来原来的左子树
        root->right=invertTree(temp);
        return root;
    }
};

方法二:迭代

迭代法的主要思想是,我们需要遍历树中所有节点,然后将每个节点的两个子树进行调换。可以用BFS的方法遍历树中节点,并将未访问的节点存放在queue中,也可以用先序遍历等(但非递归地遍历还是BFS比较容易写)

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL) return NULL;
        queue<TreeNode*> queue;
        queue.push(root);
        while(!queue.empty()) //队列非空则一直进行 
        {
			TreeNode* first=queue.front(); 
			TreeNode* temp=first->left;  //交换左右子树
			first->left=first->right;
			first->right=temp;
			if(first->left!=NULL) queue.push(first->left); //子树非空则添加进队列
			if(first->right!=NULL) queue.push(first->right);
			queue.pop();  //将队列头pop出去
		} 
		return root;
    }
};
112. 路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 
给定如下二叉树,以及目标和 sum = 22,
		  5
         / \
        4   8
       /   / \
      11  13  4
     /  \      \
    7    2      1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

分析:解决该问题,我们需要知道,如何将问题化为子问题,如何判断一个节点是叶节点,当遍历到叶节点时如何判断。

两个子树都为空,则为叶结点。 如果是递归处理该问题,则主要判断当前的值是否与sum一致即可。

  • 如果该节点为空,则返回false
  • 否则判断该节点的是否是叶子节点,如果是叶子节点并且该值等于sum,则返回true
  • 否则向下遍历,等于两个子节点对该问题的或,当然子问题处理时 s u m − v a l sum-val sum−val,
class Solution {
public:
    bool is_leaf(TreeNode* root)
    {
        if(root->left==NULL&&root->right==NULL)
            return true;
        else
            return false;
    }
    bool hasPathSum(TreeNode* root, int sum) 
    {
        if(root==NULL) return false;
        if(root->left==NULL&&root->right==NULL&&root->val==sum)  //是叶节点并且值为sum,则返回true
            return true;
        return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
    }
};
113. 路径总和 II

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回:

[
   [5,4,11,2],
   [5,8,4,5]
]

分析:该问题需要给出路径,因此回溯法是非常可行的一种方法。

leetcode 经典回溯算法题目(思路、方法、code)

用回溯法经典套路:

  • 每次保存已经走过的路径
  • 如果到达根节点则判断是否符合,如果不符合则回溯过去,如果符合则将答案存取起来
  • 每次调用递归后,需要将状态恢复
class Solution {
public:
    vector<vector<int>> result;
    bool is_leaf(TreeNode* root)
    {
        return (root->left==NULL&&root->right==NULL);
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) 
    {
        if(root==NULL) return result;
        vector<int> road;
        backtrack(root,sum,road);
        return result;    
    }
    void backtrack(TreeNode* node,int sum,vector<int> &road) //用引用可以降低内存
    {
        if(is_leaf(node)&&sum==node->val)  //如果是叶结点并且符合要求,则将其加入
        {       road.push_back(node->val);
                result.push_back(road);
                road.pop_back();
                return ;
        }
        if(node->left!=NULL)
        {
            road.push_back(node->val);  
            backtrack(node->left,sum-node->val,road);  //向下延申
            road.pop_back();              //恢复状态
        }
        if(node->right!=NULL)
        {
            road.push_back(node->val);
            backtrack(node->right,sum-node->val,road);//向下延申
            road.pop_back();//恢复状态
        }
    }
};
236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉树中。

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

在这里插入图片描述

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

分析:

方法一:递归法

  • 首先确定一下两个节点的情况,可能其中一个就是根节点,可能都位于根的左子树,也可能都位于根的右子树,也可能一个位于左子树,一个位于右子树
  • 如果其中一个是根节点,则最近公共祖先就是根节点
  • 如果两个都位于根的左子树,则递归调用左子树即可
  • 如果两个都位于根的右子树,则递归调用右子树即可
  • 如果一个位于左子树,一个位于右子树,则最近公共祖先一定是根节点
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
	{
    	if(root==NULL) return NULL;    
    	if(root==q||root==p) return root;//如果其中一个是root,则最近公共祖先一定是root
		
		TreeNode* left=lowestCommonAncestor(root->left,p,q);
		TreeNode* right=lowestCommonAncestor(root->right,p,q);
		if(left==NULL) //说明两个节点都在右侧
			return right;
		else if(right==NULL)//说明两个节点都在左侧 
			return left;
		else  //这里表示两个都非空 ,因为两个都存在,所以不会是全空
			return root;  //说明一个在左子树,一个在右子树,因此返回root即可 
	}
};

方法二:回溯法

思路来源:如果树存储有父结点的话,实际上会很方便地把祖先节点全部遍历,然后就比较容易找到两个树的最近公共祖先,但是题目所给的树没有父节点,因此需要从root才可以得到一个节点的祖先路径。如果我们知道从root到p的路径,也知道从root到q的路径,则很容易便可以知道最近公共祖先。即两个路径的最后一个重复的节点(可以倒序遍历,第一个相同即是)

因此采用回溯法,分别找到从root到p路径和从root到q路径即可。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
	{
    	vector<TreeNode*> path1;
    	vector<TreeNode*> path2;
    	vector<TreeNode*> p_par;
		vector<TreeNode*> q_par;
		bool finish_p=false,finish_q=false; 
		backtrack(root,p,path1,p_par,finish_p); //将p_par修改为root到p的路径
		backtrack(root,q,path2,q_par,finish_q); //将q_par修改为root到q的路径
    	for(int i=min(p_par.size(),q_par.size())-1;i>=0;i--)//找两个序列的最后一个的公共
    	{
    		if(p_par[i]==q_par[i])
    		return p_par[i];
		}
        return root;
	}
    //注意这里的几个vector参数都是引用
	void backtrack(TreeNode* node, TreeNode* p,vector<TreeNode*> &path,vector<TreeNode*> &result,bool &finish)  //finish表示是否找到,用于剪枝
	{
		if(node==NULL||finish)
		  return ;
		path.push_back(node); 
		if(node==p)
		{
			finish=true;  //找到的话就将结果保存在路径中,然后finish改为true
			result=path;
			return;
		}
		backtrack(node->left,p,path,result,finish);  //左寻 
		backtrack(node->right,p,path,result,finish);//右寻 
		path.pop_back(); //恢复状态 
	}
};
114. 二叉树展开为链表

给定一个二叉树,原地将它展开为链表。

例如,给定二叉树
    1
   / \
  2   5
 / \   \
3   4   6
将其展开为:
1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

分析:

方法一:很显然,可以看出来形成的链表是一个preorder序列,因此可以采用 O ( n ) O(n) O(n)的空间复杂度,将前序遍历的顺序存入到一个vector数组中,然后按照要求使用右指针将其串联起来即可。(就是一个用空间换取时间的策略)

class Solution {
public:
	vector<TreeNode*> pre;
    void flatten(TreeNode* root) 
	{
        preoder(root);
        pre.push_back(NULL);
        for(int i=0;i<pre.size()-1;i++)  //将链表串联起来
        {
            pre[i]->left=NULL;
        	pre[i]->right=pre[i+1];
		}
    }
    void preoder(TreeNode* root)  //前序遍历,将结果存到pre中
    {
    	if(root==NULL) return;
    	pre.push_back(root);
    	preoder(root->left);
    	preoder(root->right);
	}
};

方法二:递归

每一步的过程,实际上就是 将根节点,指向 左子树的展开,然后将左子树的展开的尾节点,指向右子树的展开

递归最大的特点在于:我们只处理当前的情况,不用去管子问题是如何解决的,只需要想着子问题已经解决了,如何将该问题解决即可。

例如,例子:

    1
   / \
  2   5
 / \   \
3   4   6
\\将问题拆解

   1
 
  	    2
   		 \
          3
           \
            4
       
                  5
                   \
                    6

代码:

class Solution {
public:
    void flatten(TreeNode* root) 
	{
        if(root==NULL) return;
        flatten(root->left);
        flatten(root->right);
        if(root->left==NULL)
			return;
		TreeNode*le=root->left;
		while(le->right!=NULL)  //找到左子树的最右边的节点,也就是展开后的尾结点 
        {
        	le=le->right;
		}
		le->right=root->right; //将左子树展开后的尾部指向右子树的头部
		root->right=root->left; //将左子树移到右边
        root->left=NULL; //左指针赋为空
    }
};

方法三:非递归

分析该树的展开,实际上每一次我们是先遍历根节点,然后先序遍历左子树,然后先序遍历右子树。因此,如果我们每一步,将右子树放置在左子树最右的节点(也就是将左子树展开后最后的节点),将不影响顺序。根据此,可以用循环的方式解决该方法。

class Solution {
public:
    void flatten(TreeNode* root) 
	{
        while (root != NULL) 
		{
            if (root->left != NULL) 
			{
                TreeNode* most_right = root->left; //左子树的最右节点 
                while (most_right->right != nullptr) 
					most_right = most_right->right; // 找最右节点
                most_right->right = root->right; // 将当前root的右子树放置在左子树最右节点的子节点处
				 
                root->right = root->left; //将root->right指向left即可 
                root->left = NULL; //置空左儿子 
            }
            root = root->right; // 继续下一个节点
        }
        return;
    }
};
102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:
二叉树:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果: [[3],[9,20],[15,7] ]

分析:二叉树的层序遍历,也就是宽度优先搜索BFS遍历。如果将结果以一个数组的形式存储的话将变得容易很多,以层次存储,就需要考虑当前节点是第几层,因为需要将同层的放置在一起,解决这个问题可以用将添加节点和添加队列元素分开的方法。

class Solution {
public:
    vector<vector<int> > levelOrder(TreeNode* root) 
	{
        vector<vector<int> > result;//存储结果
		queue<TreeNode*> Q; //BFS的队列
		if(root==NULL) return result;
		Q.push(root);
		while(!Q.empty())
		{
			 vector<int> f; //存储这一层的答案
			 int size=Q.size(); //每一次添加前,记录size,这样只将队列的前size个val存储,等价于记录了树的深度,使同深度的节点一起
			 for(int i=0;i<size;i++)  //遍历size个节点,也就是将这一层遍历结束就停止 
			 {
			 	TreeNode* tem=Q.front();
			 	f.push_back(tem->val);
				if(tem->left!=NULL) Q.push(tem->left);
				if(tem->right!=NULL) Q.push(tem->right); 	
				Q.pop();
			 }
			 result.push_back(f);	//将当前结果存储
		} 
        return result;
    }
};
144. 二叉树的前序遍历

给定一个二叉树,返回它的 前序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]

分析:二叉树的前序遍历中序遍历后序遍历都有递归与非递归方式,通常来说,递归方式是非常简洁且容易写的,但非递归方式还是要掌握比较好。

前序遍历的递归方式:

  • 遍历二叉树的根节点
  • 如果左子树非空,则先序遍历左子树
  • 如果右子树非空,则先序遍历右子树
class Solution {
public:
    vector<int> result;
    vector<int> preorderTraversal(TreeNode* root) 
    {
        if(root==NULL) return result;  //如果是空,则返回
        result.push_back(root->val);  //将根节点的值加入
        preorderTraversal(root->left); //先序遍历左子树
        preorderTraversal(root->right); //先序遍历右子树
        return result;
    }
};

非递归方式:

可以借助一个辅助栈,先序遍历是先访问根节点,然后访问左子树,然后访问右子树。借助栈,首先将根节点入栈,与BFS遍历二叉树的层次类似,然后将右节点入栈,然后入栈左节点,将当前元素pop。每次取栈顶元素重复操作。

  1. 首先将根节点入栈
  2. 将栈顶元素取出后弹出,将该节点对应的值存储起来,如果该元素的右子树非空,则将右子树放入栈,如果该元素的左子树非空,则将左子树入栈
  3. 重复步骤2,直至栈为空
class Solution {
public:
    vector<int> result;
    vector<int> preorderTraversal(TreeNode* root) 
    {
        stack<TreeNode*> st;//辅助栈
        if(root==NULL) return result;
        st.push(root);//将根节点放入栈顶
        while(!st.empty())
        {
            TreeNode* temp=st.top();  //取栈顶后将其pop
            st.pop();
            result.push_back(temp->val);     
            if(temp->right!=NULL) st.push(temp->right);//先存右子树,再存左子树
            if(temp->left!=NULL) st.push(temp->left);
        }
        return result;
    }
};
199. 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

分析:右视图,也就是每一层的最右边的元素,因此可以考虑在层次遍历的基础上,记录每一层的最后一个元素即可,因此,掌握层序遍历的话搞定该题应该是较为容易的。

如果在每次遍历一层后重新读取size,就可以等价于更新了新的层数,否则的话就需要存储层数,那样的话可以考虑用paire的方式将每个节点与层数联系起来。

class Solution {
public:
    vector<int> rightSideView(TreeNode* root)
	{
        vector<int> result;//存储结果
		queue<TreeNode*> Q; //BFS的队列
        TreeNode* tem;
		if(root==NULL) return result;
		Q.push(root);
		while(!Q.empty())
		{
	   int size=Q.size(); //每一次添加前,记录size,这样只将队列的前size个val存储,等价于记录了树的深度,使同深度的节点一起
			 for(int i=0;i<size-1;i++)  //遍历前size-1个节点时只将其左右子树存储即可 
			 {
			 	tem=Q.front();
				if(tem->left!=NULL) Q.push(tem->left);
				if(tem->right!=NULL) Q.push(tem->right); 	
				Q.pop();
			 }
             tem=Q.front(); //此时的front就是一层的最后一个节点
             result.push_back(tem->val);
             if(tem->left!=NULL) Q.push(tem->left);
			 if(tem->right!=NULL) Q.push(tem->right); 	
			 Q.pop();     
        } 
        return result;
    }
};
105. 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:
    3
   / \
  9  20
    /  \
   15   7

分析:重构二叉树的条件是已知中序序列以及前序序列和后序序列的其中一个。

该题中,已知前序序列和中序序列。

首先考虑这两种序列的遍历形式:

前序序列:先遍历根节点,然后左子树,然后右子树

中序序列:先遍历左子树,然后根节点,然后右子树

因此,我们已知前序序列,则前序序列的第一个元素是根节点内容。然后根据该节点的值,在中序序列中找到该值的位置,则可以根据中序序列确定出左子树和右子树的元素集合。根据由中序序列得到的左子树和右子树的中序遍历,可以在前序序列中找到左子树和右子树的前序遍历序列。因此,很容易考虑递归即可。

(该代码由于每次将新的子树序列进行生成,因此空间和时间上都不优秀,可以再写一个函数,不去生成新的子列,只标记一下每个子列的起始和结束位置即可)。

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
        if(preorder.size()==0)
			return NULL;
		TreeNode *root = new TreeNode(preorder[0]);
		vector<int> pre_before;
		vector<int> pre_after;
		vector<int> vin_before;
		vector<int> vin_after;
		int st=0;
		while(preorder[0]!=inorder[st])
		{
			st++;
		} //st表示中序遍历根的位置
		for(int i=0;i<st;i++)
		{
			vin_before.push_back(inorder[i]);
		}
		for(int i=st+1;i<inorder.size();i++)
		{
			vin_after.push_back(inorder[i]);
		}
		for(int i=1;i<=vin_before.size();i++)
		{
			pre_before.push_back(preorder[i]);
		}
		for(int i=pre_before.size()+1;i<preorder.size();i++)
		{
			pre_after.push_back(preorder[i]);
		} 
		root->left=buildTree(pre_before,vin_before);
		root->right=buildTree(pre_after,vin_after);
		return root;
    }
};
101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
    1
   / \
  2   2
   \   \
   3    3

分析:一个树何时是镜像对称的,即一个树的左右两个子树是镜像对称的。

因此,如何才能判断两个数是镜像对称的?

使用递归:

  • 如果两个树都是空,说明是镜像对称的
  • 如果两个树根节点的值相同且一个树的左子树与另一个树的右子树镜像对称,一个树的右子树和另一个树的左子树镜像对称,则两个树是镜像对称的
  • 以上如有一个不成立,则不对称
class Solution {
public:
    bool isSymmetric(TreeNode* root) 
    {
        if(root==NULL) return true;
        return isSymmetric(root->left,root->right);    
    }
    bool isSymmetric(TreeNode* node1,TreeNode* node2)
    {
        if(node1==NULL&&node2==NULL) return true;
        if(!(node1!=NULL&&node2!=NULL)) return false; //两个其中一个是NULL
        return (node1->val==node2->val)&&isSymmetric(node1->left,node2->right)&&isSymmetric(node1->right,node2->left);
    }
};
104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。

分析:很显然递归可以较好的解决该问题,如果根节点不为空,则二叉树的最大深度等于 1+max(左子树最大深度,右子树最大深度)

class Solution {
public:
    int maxDepth(TreeNode* root) 
    {
        if(root==NULL) return 0;
        return 1+max(maxDepth(root->left),maxDepth(root->right));        
    }
};

由于每个节点都遍历一遍,因此时间复杂度为 O ( n ) O(n) O(n), 空间复杂度为 O ( l o g n ) O(logn) O(logn) ,最坏情况下树为直线,则空间复杂度将为 O ( n ) O(n) O(n)

111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回它的最小深度  2

分析:和上题类似,但是这里需要注意最小深度是到最近的叶子节点,因此如果左子树为空,应该为1+右子树的最小深度,如果右子树为空,应该为1+左子树的最小深度。否则应该是1+min(左子树最小深度,右子树最小深度)

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root==NULL) return 0;
        if(root->left==NULL)
            return 1+minDepth(root->right);
        if(root->right==NULL)
            return 1+minDepth(root->left);
        return 1+min(minDepth(root->left),minDepth(root->right));      
    }
};
leetcode二叉搜索树经典题目(思路、方法、code) 文章目录二叉搜索树的简介[98. 验证二叉搜索树](https://leetcode-cn.com/problems/validate-binary-search-tree/)[700. 二叉搜索树中的搜索](https://leetcode-cn.com/problems/search-in-a-binary-search-tree/)[701. 二叉搜索树中的插入操作](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) 阅读详情

相关推荐

LeetCode面试经典150题:高效算法刷题指南

算法与数据结构是技术面试的核心考察点,掌握常见题型和解题思路对求职至关重要。LeetCode经典150题精选了面试中最常出现的算法问题,覆盖数组、链表、树、动态规划等关键数据结构。通过系统化的刷题方法,如五步刷题法和错题本策略,可以有效提升解题能力。动态规划和二叉树等高频题型需要特别关注,理解其底层原理和应用场景。本文结合工程实践,分享如何高效准备算法面试,包括刷题计划制定、面试解题步骤和常见问题应对策略,帮助开发者在有限时间内最大化提升算法能力。

weixin_34168880的博客 361

二叉树常见解题方法

文章目录一、利用递归遍历框架解题题目1:二叉树的深度(leetcode)题目2:二叉树的直径(leetcode)1、特殊场景-两个节点同时遍历题目3:对称二叉树(leetcode)题目4:填充每个节点的下一右侧节点指针(leetcode)2、特殊场景-构建二叉树二、利用层次遍历解题题目6:二叉树的层序遍历(leetcode)题目7: 填充每个节点的下一个右侧节点指针(leetcode) 一、利用递归遍历框架解题 二叉树解题重点在于利用思考根节点、左子树、右子数的关系,其余工作交给遍历处理,二叉树递归基本框架

u012866052的博客 2449

LeetCode 面试经典 150 题回顾

最经典 150 题,掌握面试所有知识点 面试经典 150 题 : 题目分析、解题思路、复杂度分析、代码展示

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 8万+

二叉树的题目练习总集(一次做到爽)

摘要:建立二叉树、前中后层序、求树高度、叶子结点个数、k层结点个数、结点是否存在于二叉树、两个叶子最近公共祖先、判断平衡树、求二叉树最远两个结点距离。 目录 分析需求: 一、节点 二、队列 三、树 1、树的基本方法:建立二叉树。 2、求前中后层遍历 3、求树的高度: 4、求叶子节点个数 5、求二叉树第k层的结点个数 6、判断一个结点是否在二叉树中? 7、求两个结点的...

雀黑够呛哥 3203

计算机数据结构二叉树测试题

,包含数据结构中二叉树的许多试题包

计算机二级二叉树试题专题

计算机二级二叉树专题 主要介绍有关二叉树的知识点和二叉树题型的解法

LeetCode刷题------二叉树

跟着代码随想录学二叉树

weixin_43526403的博客 426

PyTorch、Torchvision、Torchaudio历史版本whl文件下载地址、版本对应关系与离线安装全攻略

本文详细解析了PyTorch、Torchvision和Torchaudio历史版本whl文件的下载地址、版本对应关系及离线安装全攻略。针对无网络环境下的安装挑战,提供了官方whl文件获取路径、版本匹配技巧和完整安装流程,帮助开发者高效解决兼容性问题,确保深度学习环境的稳定部署。

weixin_31960565的博客 378

1.二叉树的解题思路(基础篇)

算法学习的积累旅程~

wang19970515的博客 193

第7篇-SAP MM模块-JIT应用实战解析,从计划协议到JIT供应的关键配置与流程

本文深入解析SAP MM模块中的JIT(Just In Time)供应模式,从计划协议到JIT供应的关键配置与流程。通过动态计划行管理、需求聚合与分解等核心功能,实现精确数量、时间和地点的物料供应。文章详细介绍了主数据准备、计划协议配置、MRP参数精调及EDI集成方案,并提供了实施中的典型问题与解决方案,助力企业优化供应链管理。

weixin_30363509的博客 948

Linux下libdrm实战:从零搭建一个简单的DRM显示程序(附完整代码)

本文是一份Linux下libdrm的实战指南,详细介绍了如何从零开始搭建一个简单的DRM显示程序。通过对比传统Framebuffer的局限性,阐述了现代DRM架构的核心优势与核心对象(FrameBuffer、Plane、CRTC等)的协作流程。文章提供了完整的代码示例,演示了如何打开设备、创建并填充Dumb Buffer、设置CRTC以依次显示红绿蓝纯色画面,并涵盖了编译、运行及进阶开发要点,为嵌入式Linux图形开发提供了扎实的入门基础。

weixin_29183637的博客 407

计算机二级:树与二叉树速记公式及特殊例题

简单整理计算机二级树与二叉树相关公式概念,无废话,有错误请指出我没太费心思,公式、例题均来自网络及视频。

FBJSSSSS的博客 1万+

51单片机独立按键控制LED(二)

对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动。独立按键控制LED显示二进制。独立按键控制LED灯亮灭。独立按键控制LED状态。独立按键控制LED移位。

m0_50562428的博客 5383

LeetCode 力扣算法题解汇总,All in One

我刷过的所有 leetcode 算法题解的汇总。 题目的排列顺序是按照先Easy再Medium再Hard排列的,暂时还没有把题目全部整理完成。后序我会把刷过的所有的题目都整理到这个文档里。 如果想看我全部的力扣算法题解,可以看我的题解博客:[fuxuemingzhu.cn](fuxuemingzhu.cn)

负雪明烛 1万+

ArcGIS+PLUS+InVEST三件套实战:从零搞定土地利用变化与碳储量预测(附完整数据包)

本文详细介绍了如何整合ArcGIS、PLUS模型和InVEST模型,构建土地利用变化与碳储量预测的完整研究流水线。通过多情景模拟和生态系统服务评估,提供从数据准备到结果验证的实战指南,助力研究者高效完成生态评估项目。

weixin_30399821的博客 544

TMC2240 芯片数据手册解读|第十三篇 StallGuard4负载测量(StallGuard4 Load Measurement)

摘要: TMC2240的StallGuard4技术专为StealthChop2静音模式设计,通过SG4_RESULT实时测量电机负载,实现堵转检测、无传感器回零和CoolStep节能。其核心原理基于负载角检测,通过SG4_THRS阈值调节灵敏度,并支持四通道独立测量(SG4_IND_0~3)优化相位平衡。独特功能包括无抖动模式切换补偿(sg_angle_offset),解决StealthChop2与SpreadCycle切换时的电流突变问题。调优时需结合SG4_THRS设定与DIAG验证,确保堵转精准触发。

BackCatK Chen的博客 303

【GitHub项目推荐--LeetCodeAnimation:用动画的形式呈现LeetCode题目思路】

​​ 是一个创新的开源项目,由MisterBooo(吴师兄)创建,致力于用动画的形式演示LeetCode题目的解题思路。该项目通过直观的动画可视化,帮助开发者更好地理解和掌握算法和数据结构的核心概念,让抽象的算法变得生动易懂。🔗 ​GitHub地址🚀 ​核心价值​:动画演示 · 算法可视化 · 学习辅助 · 直观理解​项目背景​:​学习痛点​:解决算法学习抽象难懂的问题​视觉学习​:利用动画提升学习效果和理解深度​创新教学​:创新的算法教学方法​长期规划​:3-4年完成所有题目动画化​。

j8267643的博客 1060

二极管钳位电路、限幅电路和检波电路Multisim电路仿真

本文系统介绍了二极管钳位、限幅和检波三种基础电路的工作原理及Multisim仿真验证。钳位电路通过电容-二极管配合实现波形整体平移,将波峰或波谷固定在指定电压;限幅电路利用二极管导通特性削除信号超出设定阈值的部分;检波电路则通过半波整流和电容滤波从调幅波中提取音频信号。三种电路均通过Multisim仿真验证了理论分析结果,展示了二极管在信号处理中的关键作用。这些基础电路广泛应用于信号调理、电平保护和通信解调等领域。

XU157303764的博客 1125

10 道经典的 LeetCode 题目,结合 C++ 语言的实现,每道题目都包含详细的分析过程、代码实现和示例输出

以下是 10 道经典的 LeetCode 题目,结合 C++ 语言的实现,每道题目都包含详细的分析过程、代码实现和示例输出。

分享平时的学习心得和笔记 1097

YOLO26 实战全流程:从数据集标注到端到端无NMS推理(完整版,附ProgLoss核心调参技巧+避坑指南)

本章节是实战经验的精华❌ 数据集标注不规范,导致模型精度低 → ✅ 严格遵守工业级标注规范,标注框紧贴目标边缘,不要漏标/多标;❌ 训练时未使用预训练权重,导致收敛极慢 → ✅ 必须开启,预训练权重能让模型快速收敛;❌ ProgLoss参数调整幅度过大,导致训练崩溃 → ✅ 每次只调整一个参数,幅度±0.02即可,循序渐进;❌ 推理时强行添加NMS参数,画蛇添足 → ✅ YOLO26无需NMS,推理命令中不要加conf/iou参数,否则会降低推理速度;

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1141

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

二叉树所有路径求解(力扣257)

以上就是针对这道题的刷题笔记,讲解了怎么用递归以及回溯求解二叉树的所有路径问题,用前序遍历遇到叶子结点时则回溯到上面去重新遍历,还用到了stringbuilder来拼接字符串。

Huahua_1223的博客 1396

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【算法比赛】2020 力扣杯!Code Your Future 春季全国编程大赛

这个比赛,除了最后一题,其他四题其实没啥难度。 第一题:字符串操作。 第二题:模拟。 第三题:分析。 第四题:DP。 详细题解如下。 1.重新格式化字符串(Reformat the String) AC代码(C++) 2.点菜展示表(Display Table of Food Orders in A Restaurant) AC代码(C+...

Mikchy的博客 2063

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

如何优雅地刷力扣 LeetCode - Easy

App > LeetCode > 题库 > 题解。

媛媛 854

【leetcode刷题】26.翻转二叉树——Java版

欢迎订阅《leetcode》专栏

公号:一条coding 1万+

leetcode 二叉树进阶题目

二叉树进阶题目

apigthatcanfly的博客 269

力扣257. 二叉树的所有路径(遍历思想解决)

力扣257. 二叉树的所有路径(遍历思想解决)

LNsupermali的博客 940
上一篇: 归并排序和逆序数(思路、code)
下一篇: leetcode二叉搜索树经典题目(思路、方法、code)
coding丁
博客等级 码龄9年 383粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值