【二叉树】(二)二叉树的基础修改构造及属性求解1

news2024/9/22 21:35:41

(二)二叉树的基础修改构造及属性求解1

  • 翻转二叉树
    • 递归实现
    • 迭代实现(深度遍历)
    • 层序实现(广度遍历)
  • 对称二叉树
    • 递归实现
    • 迭代实现(非层序遍历)
  • 二叉树的最大深度
    • 递归法
    • 迭代法(层序遍历)
  • 二叉树的最小深度
    • 解题思路
    • 递归法
    • 迭代法(层序遍历)
  • 完全二叉树的节点个数
    • 普通二叉树
    • 完全二叉树
  • 平衡二叉树

翻转二叉树

力扣原题链接:226. 翻转二叉树
给定一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

这道题目是非常经典的题目,也是比较简单的题目

思路:

  • 注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果**
  • 这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次! 拿纸画一画,就理解了

递归实现

1. 确定递归函数的参数和返回值
  参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。
  返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode*

TreeNode* invertTree(TreeNode* root)

2. 确定终止条件
当节点为空的时候,就返回

if (root == NULL) return root;

3. 确定单层递归的逻辑
因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

swap(root->left, root->right);	//中
invertTree(root->left);			//左
invertTree(root->right);		//右

完整代码:

TreeNode* invertTree(TreeNode* root)
{
     if (root == NULL) 
     	return root;
     swap(root->left, root->right);  // 中
     invertTree(root->left);         // 左
     invertTree(root->right);        // 右
     return root;
}

后续遍历: 后续遍历顺序是左右中,因此只需要将交换放到最后一个处理即可。

TreeNode* invertTree(TreeNode* root) 
{
	if (root == NULL) 
		return root;
	invertTree(root->left);         // 左
	invertTree(root->right);        // 右
	swap(root->left, root->right);  // 中
	return root;
}

拓展: 中序遍历
  对于中序遍历是否简单的交换程序即可呢?答案是否定的。使用递归的中序遍历,某些节点的左右孩子会翻转两次。
如果非要使用递归中序的方式写,也可以,如下代码就可以避免节点左右孩子翻转两次的情况:

TreeNode* invertTree(TreeNode* root) 
{
	if (root == NULL) 
		return root;
	invertTree(root->left);         // 左
	swap(root->left, root->right);  // 中
	//注意 这里依然要遍历左孩子,因为中间节点已经翻转了
	invertTree(root->left);      	//右  
	return root;
}

迭代实现(深度遍历)

//迭代法翻转二叉树
TreeNode* invert2Tree(TreeNode* root) 
{
	if(root == NULL)
		return root;
	stack<TreeNode*> st;
	st.push(root);
	while(!st.empty())
	{
		TreeNode* node = st.top();
		st.pop();
		swap(node->left, node->right);	//中
		if(node->left)				
			st.push(node->left);		//左
		if(node->right)
			st.push(node->right);		//右	
	}
}

如果这个代码不太熟悉的话可以再回顾一下二叉树的迭代遍历。

层序实现(广度遍历)

//层序法翻转二叉树
TreeNode* invert3Tree(TreeNode* root) 
{
	queue<TreeNode*> que;
	int size;
	if(root != NULL)
		que.push(root);
	while(!que.empty())
	{
		size = que.size();
		while(size--)
		{
			TreeNode* node = que.front();
			que.pop();
			swap(node->left, node->right);	//中
			if(node->left)
 				que.push(node->left);		//左
 			if(node->right)
 				que.push(node->right);		//右
		}
	}
	return root;
}

如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以回顾一下二叉树的层序遍历。


对称二叉树

力扣原题链接:101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的

  对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

确定遍历顺序:
比较的是两个子树的里侧和外侧的元素是否相等。如图所示:

  • 本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

  • 正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

递归实现

递归三部曲

1. 确定递归函数的参数和返回值
  因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。返回值自然是bool类型。

bool compare(TreeNode* left, TreeNode* right)

2. 确定终止条件
  要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚! 否则后面比较数值的时候就会操作空指针了。

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,return true
  • 左右都不为空,且数值不相等,不对称,return false

代码如下:

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;
	//对称 处理递归单层逻辑
	else
	{
	
	}
}

3. 确定单层递归的逻辑
  此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左子树,右节点的右子树。
  • 比较内侧是否对称,传入左节点的右子树,右节点的左子树。
  • 如果左右都对称就返回 true ,有一侧不对称就返回 false

代码如下:

//判断左右节点是否对称
bool outSide = compare(left->left,  right->right);	//左子树:	左	//左子树: 右
bool inSide  = compare(left->right, right->left);	//左子树:	右	//左子树: 左	
//返回结果到父节点				
if(outSide == true && inSide == true)	//左子树:	中	//右子树: 中
	return true;
else
	return false;	
//左子树:	左右中		右子树: 右左中  都是后续遍历

如上代码中,我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)。

最后递归的C++整体代码如下:

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;
		//对称 处理递归单层逻辑
		else
		{
			//判断左右节点是否对称
			bool outSide = compare(left->left,  right->right);	//左子树:	左	//左子树: 右
			bool inSide  = compare(left->right, right->left);	//左子树:	右	//左子树: 左	
			//返回结果到父节点
			if(outSide == true && inSide == true)	//左子树:	中	//左子树: 中
				return true;
			else
				return false;	
			//左子树:	左右中		右子树: 右左中  都是后续遍历
		}
	}
}
//掉用递归函数
bool isSymmetric(TreeNode* root) 
{
	if(root == NULL)
		return true;
	bool ret = compare(root->left, root->right);
	return ret;
}
	

迭代实现(非层序遍历)

  这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历)

使用队列
通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等,如动画所示:

代码如下:

//迭代实现 使用队列
bool isSymmetric(TreeNode* root) 
{
	if(root == NULL)
		return true;
	queue<TreeNode*> que;
	//左右子树入队列
	que.push(root->left);
	que.push(root->right);
	
	while(!que.empty())
	{
		TreeNode* leftNode  = que.front();	que.pop();	//左子树根节点
		TreeNode* rightNode = que.front();	que.pop();	//右子树根节点
		if(leftNode == NULL && rightNode == NULL)		//左右子树都为空 对称
			continue;
		else if(leftNode == NULL && rightNode != NULL)
			return false;
		else if(leftNode != NULL && rightNode == NULL)
			return false;
		
		//保证节点不为空
		if(leftNode -> val == rightNode -> val)	//数值相等 继续判断子树
		{
			que.push(leftNode->left);
			que.push(rightNode->right);
			que.push(leftNode->right);
			que.push(rightNode->left);
		}
		else		//都不为空 但数值不等 不对称
			return false;
	}
	return	true;
}	

二叉树的最大深度

力扣原题链接:104. 二叉树的最大深度
给定一个二叉树 root ,返回其最大深度。
  

返回它的最大深度 3

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数

而根节点的高度就是二叉树的最大深度,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。

递归法

确定递归函数的参数和返回值: 参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。

int getHeight(TreeNode* node)

确定终止条件: 如果为空节点的话,就返回0,表示高度为0

if(node == NULL)
	return 0;

确定单层递归的逻辑: 先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度

int leftDepth  = getHeight(node->left);		//左
int rightDepth = getHeight(node->right);	//右
return 1 + max(leftDepth,rightDepth);		//中

所以整体c++代码如下:

	//递归法 递归函数
	int getHeight(TreeNode* node)
	{
		if(node == NULL)
			return 0;
		int leftDepth  = getHeight(node->left);		//左
		int rightDepth = getHeight(node->right);	//右
		return 1 + max(leftDepth,rightDepth);		//中
	}	
	int maxDepth(TreeNode* root) {
		return getHeight(root);
    }

迭代法(层序遍历)

  当然这题也可以使用迭代法,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:

所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决,只需记录二叉树的层数即可,代码如下:

//使用层序遍历
 int maxDepth(TreeNode* root)
 {
 	//入口参数检查
 	if(root == NULL)
 		return 0;
 	int depth = 0;				//树深度
 	int size = 0;				//没一层节点个数
 	queue<TreeNode*> que;	//存放节点队列
 	que.push(root);
 	
 	while(!que.empty())
 	{
 		size = que.size();	 //记录当前层节点数量
while(size--)
{	
	TreeNode* node = que.front();
 			que.pop();
  			
  		if(node->left)
		que.push(node->left);
	if(node->right)
		que.push(node->right);
}
size = que.size();	 //更新队列大小
depth++;	
}
return depth;
}

若对该程序不熟悉或对层次遍历不熟悉的话请,回顾复习二叉树的层序遍历方式。


二叉树的最小深度

力扣原题链接:111. 二叉树的最小深度

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

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

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

解题思路

直觉上好像和求最大深度差不多,其实还是差不少的。本题依然可以使用上述的后序求二叉树的高度。

但本题还有一个误区,在处理节点的过程中,最大深度很容易理解,最小深度就不那么好理解,如图:

若完整照搬修改求最大深度的程序,则求得上述概述的最小深度是1,因为在求min时,左侧的子树为空,返回0,因此需要考虑左右子树为空的情况。

递归法

确定递归函数的参数和返回值 参数为要传入的二叉树根节点,返回的是int类型的深度,代码如下:

int getMinHeight(TreeNode* node)

确定终止条件 终止条件也是遇到空节点返回0,表示当前节点的高度为0,代码如下:

if(node == NULL)
	return 0;

确定单层递归的逻辑
这块和求最大深度可就不一样了,可能会模仿求最大深度写成如下代码:

int leftDepth  = getMinHeight(node->left);	//左
int rightDepth = getMinHeight(node->right);	//右
return 1 + min(leftDepth, rightDepth);		//中

这个代码就犯了此图中的误区:

如果这么求的话,没有左孩子的分支会算为最短深度。

所以,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。

反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。

代码如下:

int leftDepth  = getMinHeight(node->left);		//左
int rightDepth = getMinHeight(node->right);		//右

//中
//左子树为空 返回右侧深度
if(node->left == NULL && node->right != NULL)
	return rightDepth + 1;
//右子树为空 返回左侧深度
else if(node->left != NULL && node->right == NULL)
	return leftDepth + 1;
//返回左右子树最深度
else
	return 1 + min(leftDepth, rightDepth);	

遍历的顺序为后序(左右中),可以看出:求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。

整体递归代码如下:

int getMinHeight(TreeNode* node)
{
	if(node == NULL)
		return 0;
	int leftDepth  = getMinHeight(node->left);		//左
	int rightDepth = getMinHeight(node->right);		//右
	
	//中
	//左子树为空 返回右侧深度
	if(node->left == NULL && node->right != NULL)
		return rightDepth + 1;
	//右子树为空 返回左侧深度
	else if(node->left != NULL && node->right == NULL)
		return leftDepth + 1;
	//返回左右子树最深度
	else
		return 1 + min(leftDepth, rightDepth);	
}
int minDepth(TreeNode* root) {
	return getMinHeight(root);
} 

迭代法(层序遍历)

当然本题还可以使用层序遍历的方式来解决,思路是一样的,如果对于层序遍历或者下列程序不清楚的话,可以回顾二叉树的层序遍历思想和程序设计。层序遍历示意图:

需要注意的是,只有当左右孩子都为空的时候,才说明遍历到最低点了。 如果其中一个孩子不为空则不是最低点
代码如下:

//迭代法 层序遍历
int minDepth(TreeNode* root) 
{
	if(root == NULL)
		return 0;
	int depth = 0;
	int size = 0;
	queue<TreeNode*> que;
	que.push(root);
	while(!que.empty())
	{
		size = que.size();	//获取队列大小
		depth++;
		while(size--)
		{
			TreeNode* node = que.front();
			que.pop();
			if(node == NULL)
				continue;
			if(node->left)
				que.push(node->left);
			if(node->right)
				que.push(node->right);
			if(node->left == NULL && node->right == NULL)
				return depth;
		}
	}
	return depth;
}

完全二叉树的节点个数

力扣原题链接:222. 完全二叉树的节点个数

给出一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

普通二叉树

  首先按照普通二叉树的逻辑来求。这道题目的递归法和求二叉树的深度写法类似而迭代法,记录遍历的节点数量就可以了,对于递归就是计算节点的左右子树的节点数量。迭代层序遍历的代码不再赘述,相信通过迭代法做完以上题目后已易如反掌的求解二叉树的节点数量。

递归遍历的顺序依然是后序(左右中),其中递归的完整代入如下所示:

//获取普通二叉树节点数量 递归算法
int getNum(TreeNode* node)
{
	if(node == NULL)
		return 0;
	//后续遍历
	int leftNum  = getNum(node->left);	//左
	int rightNum = getNum(node->right);	//右
	return leftNum + rightNum + 1;		//中
} 

完全二叉树

完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
完全二叉树情况(一)(二)如图:

因此计算完全二叉树的递归算法即判断左右子树是否为满二叉树,并返回当前节点为根节点的节点个数。

可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。

如何判断是否为满二叉树: 在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树,如果深度不等,则说明不是满二叉树,如图所示:

判断其子树是不是满二叉树,如果是则利用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归,那么 在递归三部曲中,第二部:终止条件的写法应该是这样的

//空节点
if(node == NULL)
	return 0;
	
//满二叉树 结束
int leftDepth  = 0;
int rightDepth = 0;
TreeNode* leftNode  = node->left;
TreeNode* rightNode = node->right;	
//向左遍历
while(leftNode)
{
	leftNode = leftNode->left;
	leftDepth++;
}
//向右遍历
while(rightNode)
{
	rightNode = rightNode->right;
	rightDepth++;
}
//左右深度相等 满二叉树
if(leftDepth == rightDepth)	
	return (2<<leftDepth) - 1;

单层递归的逻辑:

//单层递归逻辑
int leftNum  = getNum(node->left);	//左
int rightNum = getNum(node->right);	//右
return leftNum + rightNum + 1;		//中

最后完整的递归程序实现代码如下:

//获取完全二叉树节点数量 
//递归算法:判断子树是否为满二叉树
//满二叉树的判断:向左遍历和向右遍历的深度是一致的
//(前提:已经是一棵完全二叉树)
int getNum(TreeNode* node)
{
	if(node == NULL)
		return 0;
	
	//满二叉树 结束
	int leftDepth  = 0;
	int rightDepth = 0;
	TreeNode* leftNode  = node->left;
	TreeNode* rightNode = node->right;	
	//向左遍历
	while(leftNode)
	{
		leftNode = leftNode->left;
		leftDepth++;
	}
	//向右遍历
	while(rightNode)
	{
		rightNode = rightNode->right;
		rightDepth++;
	}
	//满二叉树
	if(leftDepth == rightDepth)	
		return (2<<leftDepth) - 1;
		
	//单层递归逻辑
	int leftNum  = getNum(node->left);	//左
	int rightNum = getNum(node->right);	//右
	return leftNum + rightNum + 1;		//中
}
int countNodes(TreeNode* root) 
{
	return getNum(root);
}

平衡二叉树

力扣原题链接:110. 平衡二叉树

给定一个二叉树,判断它是否是 平衡二叉树

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数,但leetcode中强调的深度和高度很明显是按照节点来计算的,如图:


因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)

1. 明确递归函数的参数和返回值
参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。

// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int getHeight(TreeNode* node)

2. 明确终止条件
递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0,代码如下:

if (node == NULL) {
    return 0;
}

3. 明确单层递归的逻辑
通过左子树高度和其右子树高度的差值判断是否为平衡二叉树,如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。

//计算左子树的高度 并判断是否为平衡二叉树
int leftHeight  = getHeight(node->left);
if(leftHeight == -1)	return -1;
//计算右子树的高度 并判断是否为平衡二叉树
int rightHeight = getHeight(node->right);
if(rightHeight == -1)	return -1;

//左右子树是平衡二叉树 但高度差大于1
if(abs(leftHeight - rightHeight) > 1)
	return -1;
else
	return 1 + max(leftHeight,rightHeight);

最后本题整体递归代码如下:

class Solution {
public:
	int getHeight(TreeNode* node)
	{
		if(node == NULL)
			return 0;
			
		//计算左子树的高度 并判断是否为平衡二叉树
		int leftHeight  = getHeight(node->left);
		if(leftHeight == -1)	return -1;
		//计算右子树的高度 并判断是否为平衡二叉树
		int rightHeight = getHeight(node->right);
		if(rightHeight == -1)	return -1;
		
		//左右子树是平衡二叉树 但高度差大于1
		if(abs(leftHeight - rightHeight) > 1)
			return -1;
		else
			return 1 + max(leftHeight,rightHeight);
	}
	
	bool isBalanced(TreeNode* root) {
		int ret  = getHeight(root);
		if(ret != -1)
			return true;
		else
			return false;
    }	
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1678547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

欢乐钓鱼大师攻略大全,新手钓鱼入坑必备攻略!

《欢乐钓鱼大师》是一款深受玩家喜爱的钓鱼手游&#xff0c;在游戏中&#xff0c;玩家可以通过升级和更换鱼竿来享受钓鱼的乐趣&#xff0c;并有机会钓到各种稀有鱼类。然而&#xff0c;很多玩家在闯关过程中遇到了不少困难。为了帮助大家更好地掌握游戏技巧&#xff0c;小编特…

量化交易策略:经典量化交易策略大汇总(内附开通方法)

01、什么是量化交易&#xff1f; 量化交易是一种依赖于先进的数学模型和计算机技术的交易方式&#xff0c;旨在制定能带来超额收益的多种“大概率”事件策略。 这个过程从大量的历史数据中筛选&#xff0c;极大地减少了投资者情绪波动的影响&#xff0c;避免了在市场极度狂热或…

关于FIFO Generator IP和XPM_FIFO在涉及位宽转换上的区别

在Xilinx FPGA中&#xff0c;要实现FIFO的功能时&#xff0c;大部分时候会使用两种方法&#xff1a; FIFO Generator IP核XPM_FIFO原语 FIFO Generator IP核的优点是有图形化界面&#xff0c;配置参数非常直观&#xff1b;缺点是参数一旦固定&#xff0c;想要更改的化就只能重…

【大数据】计算引擎MapReduce

目录 1.概述 1.1.前言 1.2.大数据要怎么计算&#xff1f; 1.3.什么是MapReduce&#xff1f; 2.架构 3.工作流程 4.shuffle 4.1.map过程 4.2.reduce过程 1.概述 1.1.前言 本文是作者大数据系列专栏的其中一篇&#xff0c;专栏地址&#xff1a; https://blog.csdn.ne…

AI交互数字人赋能农业数字化、智能化推广营销

2024陵水荔枝文化节上“数字新农人”陵小荔身着黎族服饰、佩戴银器亮相开幕式现场&#xff0c;AI交互数字人生动地以互动式推介和歌舞等形式&#xff0c;带领宾客们了解陵水荔枝的发展历程、产业布局、未来愿景等。如今&#xff0c;越来越多农产品品牌通过3D虚拟数字人定制&…

声纹识别的对抗与防御

随着机器学习理论和方法的发展, 出现了用于模仿特定说话人语音的深度伪造、针对语音识别和声纹识别的对抗样本, 它们都为破坏语音载体的可信性和安全性提供了具体手段, 进而对各自应用场景的信息安全构成了挑战。 深度伪造是利用生成式对抗网络等方法, 通过构建特定的模型, 产生…

用HAL库改写江科大的stm32入门例子4-1 OLED

大体 步骤&#xff1a; step1&#xff1a;使用STM32CubeMX初始化I2C1&#xff0c;生成初始化代码 step2&#xff1a;将任意一个库导入到工程&#xff0c;配置好编译路径 step3&#xff1a;调用函数即可 IIC原理图&#xff1a; 接线图&#xff1a; 先设置clock&#xff1a; 开…

GPT-4o模型介绍和使用方法

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

VBA直连SAP RFC 接口实例

引用依赖: VBA 调用 SAP API的RFC函数:RFC_READ_TABLE Sub A() 查询SAP表数据并输出到EXCEL,VBA中不区分大小写(保存后会自动把代码、变量转换大小写)Dim iData As Integer Dim nField As Integer Dim nData As Integer Dim Result As Boolean Dim vRow As Variant MsgBox…

Socks5:网络世界的隐形斗篷

在数字化时代&#xff0c;网络隐私和安全已成为人们日益关注的话题。Socks5&#xff0c;作为一种代理协议&#xff0c;为用户在网络世界中的匿名性提供了强有力的支持。本文将从Socks5的多个方面&#xff0c;深入探讨这一技术如何成为网络世界的“隐形斗篷”。 一、Socks5的基本…

如何在WordPress中启用两因素身份验证?

在WordPress中启用两因素身份验证方法&#xff1a;安装和激活WordFence安全性、启用两因素验证。 使用您可以从任何位置登录的任何门户&#xff0c;建议启用两个因素身份验证以增加帐户的安全性。 这样&#xff0c;即使有人可以正确猜测你的密码&#xff0c;它们仍然需要获得2…

代码随想录算法训练营第四十八天|121. 买卖股票的最佳时机 、122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 思路&#xff1a; 动规五部曲分析如下&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][0] 表示第i天持有股票所得最多现金 &#xff0c;这里可能有同学疑惑&#xff0c;本题中只能买卖一次&#xff0c;持有股票之…

队列的实现与OJ题目解析

"不是你变优秀了, 那个人就会喜欢你." 文章索引 前言1. 什么是队列2. 队列的实现3. OJ题目解析4. 总结 前言 感情可以培养是个伪命题. 如果有足够多的时间和爱, 就可以让另一个人爱上你的话, 那谁和谁都可以相爱了. 爱情之所以会让人死去活来, 是因为, 答案都写在了…

虚拟化技术 安装和配置StartWind iSCSI目标服务器

一、实验内容 安装StartWind iSCSI目标服务器配置StartWind iSCSI目标服务器 二、实验主要仪器设备及材料 安装有64位Windows操作系统的台式电脑或笔记本电脑&#xff0c;建议4C8G或以上配置已安装vSphere Client已创建虚拟机并在其上安装CentOS6.5StarWind安装介质starwind.…

VUE如何实现批量下载多个文件并导出zip格式

效果图 1、安装jszip和file-saver插件 npm install jszip npm install file-saver2、在所需页面引入 import JSZip from "jszip"; import FileSaver from "file-saver";3、模拟fileList数组 //fileList模拟文件数组export default {name: "notic…

react18【系列实用教程】useMemo —— 缓存数据 (2024最新版)

为什么添加了 memo &#xff0c;子组件2依然重新渲染了呢&#xff1f; 因为父组件向子组件2传递了引用类型的数据 const userInfo {name: "朝阳",};<Child2 userInfo{userInfo} />memo() 函数的本质是通过校验Props中数据的内存地址是否改变来决定组件是否重新…

《米小圈动画成语》—和孩子一起意动“神州”成语连击!

成语有着独特的语言魅力&#xff0c;以其源远流长、凝练浓缩、概括力强而历久弥新,久盛不衰&#xff0c;是中华民族特有的文化现象。成语既是语言文字符号&#xff0c;又具有无穷的艺术魅力。在表情达意、传递高质量语言信息方面起着以一当十的作用。成语的结构严谨、言简意赅&…

动规解决01背包/完全背包精讲

还不会用动态规划解决01背包/完全背包&#xff1f;看这一篇文章就够了&#xff01; 首先我们要明白什么是01背包和完全背包。 背包问题总体问法就是&#xff1a; 你有一个背包&#xff0c;最多能容纳的体积是V。 现在有n个物品&#xff0c;第i个物品的体积为vi​ ,价值为wi​…

2023年数维杯国际大学生数学建模挑战赛D题洗衣房清洁计算解题全过程论文及程序

2023年数维杯国际大学生数学建模挑战赛 D题 洗衣房清洁计算 原题再现&#xff1a; 洗衣房清洁是人们每天都要做的事情。洗衣粉的去污作用来源于一些表面活性剂。它们可以增加水的渗透性&#xff0c;并利用分子间静电排斥机制去除污垢颗粒。由于表面活性剂分子的存在&#xff…

zip压缩unzip解压缩、gzip和gunzip解压缩、tar压缩和解压缩

一、tar压缩和解压缩 tar [选项] 打包文件名 源文件或目录 选项含义-c创建新的归档文件-x从归档文件中提取文件-v显示详细信息-f指定归档文件的名称-z通过gzip进行压缩或解压缩-j通过bzip2进行压缩或解压缩-J通过xz进行压缩或解压缩-p保留原始文件的权限和属性–excludePATTE…