当前位置: 首页 > news >正文

Day 21代码|随想录| 二叉树完结撒花,今日刷题669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.吧二叉搜索树转换为累加树

提示:DDU,供自己复习使用。欢迎大家前来讨论~

文章目录

  • 二叉树 Part06
  • 二、题目
    • 题目一:669.修剪二叉搜索树
      • 解题思路:
      • 递归法
      • 迭代法:
    • 题目二: 108.将有序数组转换为二叉搜索树
      • 解题思路
      • 递归法:
      • 迭代法
    • 题目三:538.把二叉搜索树转换为累加树
      • 解题思路:
      • 递归法
      • 迭代法
    • 二叉树总结篇
      • 二叉树的理论基础
      • 二叉树的遍历方式
      • 求二叉树的属性
      • 二叉树的改造与修改
      • 求二叉搜索树的属性
      • 二叉树公共祖先问题
      • 二叉搜索树的修改与改造
  • 总结


二叉树 Part06

二、题目

题目一:669.修剪二叉搜索树

[669. 修剪二叉搜索树](https://leetcode.cn/problems/minimum-absolute-difference-in-bst/)

解题思路:

错误的思路:

直接想法就是:递归处理,然后遇到 root->val < low || root->val > high 的时候直接return NULL,一波修改,干净利落。

可以写出以下代码:

class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root == nullptr || root->val < low || root->val > high) return nullptr;root->left = trimBST(root->left, low, high);root->right = trimBST(root->right, low, high);return root;}
};

note:

但是会忽略掉删除节点的右子树,可能会存在符合的节点,但是上面的代码直接删除了,所以是不可行的。下图就是示例图:

669.修剪二叉搜索树

从图中可以看出需要重构二叉树,想想是不是本题就有点复杂了。

其实不用重构那么复杂。在上图中我们发现节点0并不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把节点0从二叉树中移除),如图:

669.修剪二叉搜索树1

递归法

  • 确定递归函数的参数以及返回值

    这里我们为什么需要返回值呢?

    因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。

    但是有返回值,更方便,可以通过递归函数的返回值来移除节点。

    TreeNode* trimBST(TreeNode* root, int low, int high)
    
  • 确定终止条件

    修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了。

    if (root == nullptr ) return nullptr;
    
  • 确定单层递归的逻辑

    如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。

    if (root->val < low) {TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点return right;
    }// 同理如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。
    if (root->val > high) {TreeNode* left = trimBST(root->left, low, high); // 寻找符合区间[low, high]的节点return left;
    }    
    

    接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。

    最后返回root节点,代码如下:

    这里可能是子树里面还有不符合要求的节点,所以还是要遍历一下的。

    root->left = trimBST(root->left, low, high); // root->left接入符合条件的左孩子
    root->right = trimBST(root->right, low, high); // root->right接入符合条件的右孩子
    return root;
    

    Q:多余的节点究竟是如何从二叉树中移除的呢?

    在回顾一下上面的代码,针对下图中二叉树的情况:

    669.修剪二叉搜索树1

    如下代码相当于把节点0的右孩子(节点2)返回给上一层,

    if (root->val < low) {TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点return right;
    }
    

    然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子(节点2) 接住。

    root->left = trimBST(root->left, low, high);
    

    此时节点3的左孩子就变成了节点2,将节点0从二叉树中移除了。

完整代码如下:

class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root == nullptr ) return nullptr;if (root->val < low) {TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点return right;}if (root->val > high) {TreeNode* left = trimBST(root->left, low, high); // 寻找符合区间[low, high]的节点return left;}root->left = trimBST(root->left, low, high); // root->left接入符合条件的左孩子root->right = trimBST(root->right, low, high); // root->right接入符合条件的右孩子return root;}
};

精简之后:

class Solution {
public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root == nullptr) return nullptr;if (root->val < low) return trimBST(root->right, low, high);if (root->val > high) return trimBST(root->left, low, high);root->left = trimBST(root->left, low, high);root->right = trimBST(root->right, low, high);return root;}
};

迭代法:

因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。

在剪枝的时候,可以分为三步:

  • 将root移动到[L, R] 范围内,注意是左闭右闭区间
  • 剪枝左子树
  • 剪枝右子树
class Solution {
public:TreeNode* trimBST(TreeNode* root, int L, int R) {if (!root) return nullptr;// 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭while (root != nullptr && (root->val < L || root->val > R)) {if (root->val < L) root = root->right; // 小于L往右走else root = root->left; // 大于R往左走}TreeNode *cur = root;// 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况while (cur != nullptr) {while (cur->left && cur->left->val < L) {cur->left = cur->left->right;}cur = cur->left;}cur = root;// 此时root已经在[L, R] 范围内,处理右孩子大于R的情况while (cur != nullptr) {while (cur->right && cur->right->val > R) {cur->right = cur->right->left;}cur = cur->right;}return root;}
};

小结:

题目二: 108.将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树

解题思路

  • 本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间
  • 因为有序数组构造二叉搜索树,寻找分割点就比较容易了。
  • 分割点就是数组中间位置的节点。

Q:如果数组长度为偶数,中间节点有两个,取哪一个?

​ 取哪一个都可以,只不过构成了不同的平衡二叉搜索树。

例如:输入:[-10,-3,0,5,9]

如下两棵树,都是这个数组的平衡二叉搜索树:

108.将有序数组转换为二叉搜索树

如果要分割的数组长度为偶数的时候,中间元素为两个,是取左边元素 就是树1,取右边元素就是树2。

这也是题目中强调答案不是唯一的原因。

递归法:

  1. 确定递归函数的返回值及参数

    这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及之前讲过的循环不变量

    // 左闭右闭区间[left, right]
    TreeNode* traversal(vector<int>& nums, int left, int right)
    
  2. 确定递归终止条件

    这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。

    if (left > right) return nullptr;
    
  3. 确定单层递归的逻辑

​ 首先取数组中间元素的位置,不难写出int mid = (left + right) / 2;这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在二分法中尤其需要注意!

​ **note:**所以可以这么写:int mid = left + ((right - left) / 2);

  • int mid = left + ((right - left) / 2);  //首先取数组中间元素的位置
    TreeNode* root = new TreeNode(nums[mid]); //取了中间位置,就开始以中间位置的元素构造节点
    root->left = traversal(nums, left, mid - 1); //接着划分区间,root的左孩子接住下一层左区间的构造节点,右孩子接住下一层右区间构造的节点。
    root->right = traversal(nums, mid + 1, right);
    return root;
    

这里int mid = left + ((right - left) / 2);的写法相当于是如果数组长度为偶数,中间位置有两个元素,取靠左边的。

整体C++代码如下:

class Solution {
private:TreeNode* traversal(vector<int>& nums, int left, int right) {if (left > right) return nullptr;int mid = left + ((right - left) / 2);TreeNode* root = new TreeNode(nums[mid]);root->left = traversal(nums, left, mid - 1);root->right = traversal(nums, mid + 1, right);return root;}
public:TreeNode* sortedArrayToBST(vector<int>& nums) {TreeNode* root = traversal(nums, 0, nums.size() - 1);return root;}
};

注意:在调用traversal的时候传入的left和right为什么是0和nums.size() - 1,因为定义的区间为左闭右闭

迭代法

迭代法可以通过三个队列来模拟,一个队列放遍历的节点,一个队列放左区间下标,一个队列放右区间下标

模拟的就是不断分割的过程,C++代码如下:

class Solution {
public:TreeNode* sortedArrayToBST(vector<int>& nums) {if (nums.size() == 0) return nullptr;TreeNode* root = new TreeNode(0);   // 初始根节点queue<TreeNode*> nodeQue;           // 放遍历的节点queue<int> leftQue;                 // 保存左区间下标queue<int> rightQue;                // 保存右区间下标nodeQue.push(root);                 // 根节点入队列leftQue.push(0);                    // 0为左区间下标初始位置rightQue.push(nums.size() - 1);     // nums.size() - 1为右区间下标初始位置while (!nodeQue.empty()) {TreeNode* curNode = nodeQue.front();nodeQue.pop();int left = leftQue.front(); leftQue.pop();int right = rightQue.front(); rightQue.pop();int mid = left + ((right - left) / 2);curNode->val = nums[mid];       // 将mid对应的元素给中间节点if (left <= mid - 1) {          // 处理左区间curNode->left = new TreeNode(0);nodeQue.push(curNode->left);leftQue.push(left);rightQue.push(mid - 1);}if (right >= mid + 1) {         // 处理右区间curNode->right = new TreeNode(0);nodeQue.push(curNode->right);leftQue.push(mid + 1);rightQue.push(right);}}return root;}
};

小结:

  1. 递归思路:提到了递归方法的核心思路是不断进行中间分割,然后递归地处理左区间和右区间,这也是一种分治策略。
  2. 递归函数的返回值:通过递归函数的返回值来增删二叉树是常规操作。
  3. 循环不变量的重要性:在定义区间的过程中,再次强调了循环不变量的重要性,这可能是在递归或迭代过程中保持逻辑一致性的关键。
  4. 迭代方法:这实际上是模拟取中间元素,然后不断分割去构造二叉树的过程。
  5. 递归与迭代的比较:虽然递归方法可能更直观,但迭代方法提供了另一种解决问题的途径,特别是在某些情况下可能更高效或更适合某些应用场景。

题目三:538.把二叉搜索树转换为累加树

538. 把二叉搜索树转换为累加树

解题思路:

  • 当我们面对累加二叉搜索树的问题时,可能会感到困惑,因为直观上它看起来比操作数组要复杂。
  • 使得每个节点 node 的新值等于原树中大于或等于 node.val 的值之和
  • 但一旦我们认识到二叉搜索树的有序性,问题就变得简单了。就像处理一个有序数组[2, 5, 13],我们可以从后向前进行累加,得到新的数组[20, 18, 13]。
  • 这种遍历方式在数组中很常见,而在二叉搜索树中,我们只需要调整遍历的顺序,采用反中序遍历(即先遍历右子树,然后是根节点,最后是左子树),就可以实现同样的顺序累加。这样一来,原本看似复杂的累加操作,就变成了一个简单的遍历和累加过程

递归法

pre指针的使用技巧: 本题依然需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。

递归三部曲:

  1. 确定递归函数的返回值和参数

    nt pre = 0; // 记录前一个节点的数值
    void traversal(TreeNode* cur)
    
  2. 确定递归函数的终止条件

    if (cur == NULL) return;
    
  3. 确定单层循环逻辑

    注意要右中左来遍历二叉树, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。

    traversal(cur->right);  // 右
    cur->val += pre;        // 中
    pre = cur->val;
    traversal(cur->left);   // 左
    

完整代码如下:

class Solution {
private:int pre = 0; // 记录前一个节点的数值void traversal(TreeNode* cur) { // 右中左遍历if (cur == NULL) return;traversal(cur->right);cur->val += pre;pre = cur->val;traversal(cur->left);}
public:TreeNode* convertBST(TreeNode* root) {pre = 0;traversal(root);return root;}
};

迭代法

迭代法其实就是中序模板题了,确定一个自己习惯的写法。

class Solution {
private:int pre; // 记录前一个节点的数值void traversal(TreeNode* root) {stack<TreeNode*> st;TreeNode* cur = root;while (cur != NULL || !st.empty()) {if (cur != NULL) {st.push(cur);cur = cur->right;   // 右} else {cur = st.top();     // 中st.pop();cur->val += pre;pre = cur->val;cur = cur->left;    // 左}}}
public:TreeNode* convertBST(TreeNode* root) {pre = 0;traversal(root);return root;}
};

二叉树总结篇

二叉树的理论基础

二叉树的种类、存储方式、遍历方式、定义方式

二叉树的遍历方式

  • 深度优先遍历
  • 广度优先遍历

求二叉树的属性

二叉树的改造与修改

求二叉搜索树的属性

二叉树公共祖先问题

二叉搜索树的修改与改造

小结:

note:二叉树的遍历顺序的选择

  • 如果是要构造二叉树,无论是普通的二叉树还是二叉搜索树,通常都是先处理根节点,也就是前序遍历。
  • 当我们想要计算普通二叉树的一些属性时,后序遍历是个不错的选择,因为这样可以在访问节点之前先得到其左右子树的信息,通常需要通过递归函数的返回值来进行计算。
  • 而对于二叉搜索树,由于其元素是有序的,中序遍历是最佳选择,因为这样可以直接利用树的有序性,比如进行排序或查找操作。

​ 注意在普通二叉树的属性中,用的是一般为后序,例如单纯求深度就用前序,二叉树:找所有路径 (opens new window)也用了前序,这是为了方便让父节点指向子节点

所以求普通二叉树的属性还是要具体问题具体分析,才能让问题变得简洁。


总结

学到了那些东西:

  • 二叉树的构造(前序构造),二叉树的遍历方式(前中后)
  • 递归和迭代,一般递归的思路来的比较简单,代码也是比较简洁。递归三部曲(1.2.3)。
  • pre指针的使用,这是一个技巧。
  • 看到二叉搜索树,一定要记得利用他的特性,有序。(在本节,迭代的代码也是比较简单的。)

关于二叉树的章节,今天是完结篇,整体下来,学的有些稀里糊涂,大概过了一边,顺了一遍思路。很多题目自己为了节省时间,还有偷懒,就没有自己亲手去敲的,不知道是因为自己太懒还是太烂,总有畏难情绪,觉得自己敲了也敲不对,敲了也没用只是浪费时间,就有些投机取巧,没有去敲。这样下来,总感觉收获很少,但哪位老板能和我说一下,你们是怎么坚持,每题都敲代码的吗?(这对我很重要)

​ 总之,二叉树,这一个章节也是结束了,马上要开始一个新的章节回溯,杜绝懒惰,从我做起,加油!!

相关文章:

Day 21代码|随想录| 二叉树完结撒花,今日刷题669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.吧二叉搜索树转换为累加树

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 二叉树 Part06二、题目题目一&#xff1a;669.修剪二叉搜索树解题思路&#xff1a;递归法迭代法&#xff1a; 题目二&#xff1a; 108.将有序数组转换为二叉搜索树解题思路递归法&#xff1a;迭代…...

cmake教程一

1. Start 1.1 构建简单工程 cmake_minimum_required(VERSION 3.0) project(Step1) add_executable(Step1 main.cpp)设置cmake最低版本要求设置工程名字设置工程生成可执行程序 2. 声明 C Standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True)如果我…...

3D场景标注标签信息,three.js CSS 2D渲染器CSS2DRenderer、CSS 3D渲染器CSS3DRenderer(结合react)

如果你想用HTML元素作为标签标注三维场景中模型信息&#xff0c;需要考虑定位的问题。比如一个模型&#xff0c;在代码中你可以知道它的局部坐标或世界坐标xyz&#xff0c;但是你并不知道渲染后在canvas画布上位置&#xff0c;距离web页面顶部top和左侧的像素px值。自己写代码把…...

C++参悟-单例模式

单例模式 一、概述1. 特点2. 实现方式3. 应用场景 二、实现代码1. 静态局部变量的懒汉单例2. 加锁的懒汉式单例3. 使用 C11 中的 std::call_one 的懒汉单例4. 饿汉式单例 一、概述 这里记录一下单例模式的最常用使用&#xff0c;单例模式&#xff08;Single Pattern&#xff0…...

【题解】—— LeetCode一周小结32

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结31 5.不含连续1的非负整数 题目链接&#xff1a;600. 不含连续…...

详解线索分层的目的、维度与创新实践

线索分层是一个系统性的过程&#xff0c;旨在更有效地管理、跟踪和利用线索资源。这一过程可以借鉴多种策略和方法&#xff0c;特别是在用户运营和市场营销中。 1、线索分层的目的 线索分层的主要目的是根据线索的不同特征或成熟度&#xff0c;将其分类管理&#xff0c;以便更…...

于8月21号的回顾

傍晚的日落和逐渐深邃的夜&#xff0c;驱散了白天的极致闷热。倦怠和疲惫充斥着大脑&#xff0c;喧嚣的浮沉又在耳边轰鸣。 我不曾想到&#xff0c;再次打开博客已经是两年后的今天了。手指轻轻滑过鼠标&#xff0c;博客的页面缓缓加载&#xff0c;那些被时间尘封的记忆瞬间涌…...

Abstract Class抽象类

抽象类&#xff08;Abstract Class&#xff09;在面向对象编程中是一种特殊的类&#xff0c;它不能被实例化&#xff0c;即不能创建该类的对象。抽象类主要用于定义一组接口&#xff08;即方法&#xff09;&#xff0c;这些方法的具体实现由子类来完成。抽象类通常用于表示一种…...

webrtc ns 降噪之粉红噪声参数推导

webrtc中降噪中&#xff0c;前50帧需要进行简单噪声估计&#xff0c;使用白噪声和粉红噪声模型估算。 首先我们 复习 有色噪声&#xff08;包含白噪声&#xff09;的一般模型&#xff1a; S(f) 是频率 f 处的功率谱密度。f是频率。α 是一个频谱指数&#xff0c;通常在1左右。…...

IO进程线程8月21日

1&#xff0c;思维导图 2&#xff0c;登录 #ifndef __LOG_H__ #define __LOG_H__ #include<myhead.h> typedef struct {char name[20];char pwd[20]; }str;int regist();int login(); #endif#include"log.h" int login() {char a[20]"\n";str p,s;…...

Web安全:SqlMap工具

一、简介 sqlmap 是一款开源的渗透测试工具&#xff0c;可以自动化进行SQL注入的检测、利用&#xff0c;并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合&#xff0c;其中包括数据库指纹识别、数据读取和访问底层文件系统…...

用手机写一本电子书

第1步、进入Andi.cn网站 第2步、点击登录&#xff0c;注册用户 第3步、点击去创作&#xff0c;进入创作页面 第4步、点击右下角的小笔&#xff0c;写一篇文章 第5步、下翻&#xff0c;点击提交按钮 第6步、再写一篇文章 第7步、点击栏目设计 第8步、进入栏目设计&#xff0c;点…...

【网络编程】基于UDP的TFTP文件传输

1&#xff09;tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再…...

Vue 3 + Pinia 实现网页刷新功能

概述 在现代 Web 开发中&#xff0c;保持用户界面的动态性和响应性至关重要。当用户触发某些操作时&#xff0c;例如点击按钮或者完成表单提交&#xff0c;我们往往需要刷新页面的一部分来展示最新的数据。本文将介绍如何使用 Vue 3 和 Pinia 来实现这一功能。 技术栈 Vue 3…...

DVWA综合靶场漏洞讲解

目录 综合靶场漏洞讲解 Brute Force Low Medium High Command Injection Low Medium High File Inclusion Low,Medium,High File Upload Low Medium High SQL Injection Low Medium High SQL Injection (Blind) Low Medium High XSS&#xff08;DOM&am…...

实现Bezier样条曲线

1.给出n1 个控制点pk(xk,yk,zk),这里k可取值0-n,多项式函数公式如下 获取的单个点的代码 void zmBezier::getPoint(float u, double p[3]) {int n m_count - 1;double x 0, y 0, z 0;for(int k 0; k < n; k){x m_ctrlPoints[k][0] * BEZ_k_n(n, k, u);y m_ctrlPoin…...

MySQL中的EXPLAIN的详解

一、介绍 官网介绍&#xff1a; https://dev.mysql.com/doc/refman/5.7/en/explain-output.htmlhttps://dev.mysql.com/doc/refman/8.0/en/explain-output.htmlexplain&#xff08;执行计划&#xff09;&#xff0c;使用explain关键字可以模拟优化器执行sql查询语句&#xff…...

LearnOpenGL——SSAO学习笔记

LearnOpenGL——SSAO学习笔记 SSAO一、基本概念二、样本缓冲三、法向半球四、随机核心转动五、SSAO着色器六、环境遮蔽模糊七、应用SSAO遮蔽因子 SSAO 一、基本概念 环境光照是我们加入场景总体光照中的一个固定光照常量&#xff0c;它被用来模拟光的散射(Scattering)。散射应…...

[C语言]-基础知识点梳理-文件管理

前言 各位师傅们好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解文件管理的相关知识&#xff0c;也就是常见的 读取&#xff0c;删除一类的操作 文件 为什么要使用文件&#xff1f; 程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&…...

pcdn闲置带宽被动收入必看教程。第五讲:光猫更换和基础设置

PCDN闲置带宽被动收入必看教程 —— 第五讲&#xff1a;光猫更换和基础设置 为了从闲置带宽中获得被动收入&#xff0c;高效的网络设备至关重要。运营商提供的光猫通常能满足日常家用需求&#xff0c;但对于PCDN应用来说&#xff0c;它们可能不足以提供所需的高性能和稳定性。…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...