数据结构之初始二叉树(4)

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏:数据结构(Java版)

二叉树的基本操作

二叉树的相关刷题(上)通过上篇文章的学习,我们简单的了解了二叉树的相关操作。接下来就是有关二叉树的经典题型练习。

二叉树的相关刷题(上)

上一篇也是有关二叉树的经典题型。沿着上篇接着开始学习。

目录

二叉树的前序遍历

二叉树的层序遍历

二叉树的层序遍历 II

从前序与中序遍历序列构造二叉树

二叉树的最近公共祖先

根据二叉树创建字符串


二叉树的前序遍历

题目:

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

输入:root = [1,null,2,3]
输出:[1,2,3]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

示例 4:

输入:root = [1,2]
输出:[1,2]

示例 5:

输入:root = [1,null,2]
输出:[1,2]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

这个题目如果用递归去做那就比较简单了,但是现在我们要采用非递归的方法来写。

思路:利用栈,将遍历到的所有根结点都入栈(以前序遍历的路线去走) ,并且将这些节点都放入List当中。当遇到 null 时,就开始出栈顶的元素,并且以栈顶元素的 right 指针来重新遍历这棵树,直至栈为空即可。

代码实现:

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if (root == null) {return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;// 因为第一次时,这个循环进不来,所以就加了 cur != null 这个条件while (cur != null || !stack.isEmpty()) {while (cur != null) {// 根结点stack.push(cur);list.add(cur.val);// 左子树cur = cur.left;}TreeNode top = stack.pop();// 右子树cur = top.right;}return list;}
}

既然前序遍历的代码出来了,那么中序遍历和后序遍历也就可以搞定了。

中序遍历:

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if (root == null) {return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {while (cur != null) {// 左子树stack.push(cur);cur = cur.left;}TreeNode top = stack.pop();// 根结点list.add(top.val);// 右子树cur = top.right;}return list;}
}

后序遍历:

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new LinkedList<>();if (root == null) { return list;}Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;TreeNode prev = null; // 记录添加的前一个位置(防止死循环)while (cur != null || !stack.isEmpty()) {while (cur != null) {stack.push(cur);cur = cur.left;}// 注意这里不能是pop,因为我们不能确定这个节点的右边是否还有节点TreeNode top = stack.peek();// 如果右边还有元素,那就得去遍历它;否则,就打印(左为null,右也为null)if (top.right == null || top.right == prev) { // 右边被处理过才能进来list.add(top.val);prev = stack.pop(); // 更新为前一个位置的值 } else {cur = top.right;}}return list;}
}

 总结:其实只要我们知道遍历的顺序,从遍历顺序去解决,那么这种题目就迎刃而解了。

二叉树的层序遍历

题目:

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

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

思路:通过队列来存储树中的节点,先储存根结点,再把根结点出队,判断左右子树是否为空,来使其入队。 

代码实现:

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ret = new LinkedList<>();// 通过队列进行层序遍历if (root == null) {return ret;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {List<Integer> list = new LinkedList<>();// 记录每一层的个数int size = queue.size();    // 先把每一层的节点都放到list中while (size-- > 0) {TreeNode cur = queue.poll();list.add(cur.val);if (cur.left != null) {queue.offer(cur.left);}if (cur.right != null) {queue.offer(cur.right);}}// 再把每一层的list放到总的ret中ret.add(list);}return ret;}
}

刚刚我们是从上往下遍历这棵树的,现在如果让我们从下往上遍历这棵树呢?

二叉树的层序遍历 II

题目:

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

思路:从上往下我们已经知道了该怎么遍历,但是从下往上不知道该从何下手?这是我们就可以采用换汤不换药的方法了。即将从上到下的遍历结果储存起来,然后再交换两者的值即可。这样我们最终得到的值就是从下往上遍历的结果了。

代码实现:

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> ret = new LinkedList<>();if (root == null) {return ret;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {List<Integer> list = new LinkedList<>();int size = queue.size();while (size-- > 0) {TreeNode cur = queue.poll();list.add(cur.val);if (cur.left != null) {queue.offer(cur.left);}if (cur.right != null) {queue.offer(cur.right);}}ret.add(list);}// 现在ret中是按照从上往下的顺序存储的,我们需要的刚好相反,即需要交换swap(ret);return ret;}private void swap(List<List<Integer>> ret) {int left = 0;int right = ret.size()-1;while (left < right) {// 交换List<Integer> tmp = ret.get(left);ret.set(left, ret.get(right));ret.set(right, tmp);left++;right--;}}
}

还有一种实现方式:就是在插入时,我们不采用尾插的方式,采用头插的方式去构建LIst。

// 采用头插的方式
ret.addFirst(list);

前序遍历、中序遍历、后续遍历的迭代版实现和层序遍历的实现所用的数据结构不同的原因:

不管是前序遍历、中序遍历还是后序遍历,都是左子树的遍历顺序在前,右子树的遍历顺序在后,这就导致了一个问题:如果根结点找不到了(先打印了,就出队列了),那么怎么去找右子树呢?因此我们的需求就是把二叉树的根结点存储起来,即让其最后再出去。这个的效果就是先进后出——> 栈 ;而层序遍历就没有这样的需求了,即从上往下、从左往右依次遍历打印,那么我们打印完这一层的节点之后,就可以舍弃它们了。即先进先出——>队列。

前面我们学习了给了前序和中序遍历或者后续和中序遍历,来构建二叉树,现在我们就用代码来实现一下: 

从前序与中序遍历序列构造二叉树

题目: 

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

思路:与我们做选填是一样的。通过前序遍历来确定二叉树的根结点,再通过根结点在中序遍历中的位置来确定左子树和右子树,而前序遍历往后,就是左子树的根结点,再确定在中序遍历中的位置来确定左子树的根结点的左子树和右子树。一直这样递归下去,直至左子树的下标大于右子树的下标(在中序遍历中) 。

代码实现: 

class Solution {// 创建一棵二叉树,先创建根结点,再创建左子树和右子树// 根结点就是根据前序遍历来找,// 左子树和右子树都是根据前序遍历和中序遍历来找出左子树和右子树的根结点private int rootIndex;public TreeNode buildTree(int[] preorder, int[] inorder) {return buildTreeChild(preorder, inorder, 0, inorder.length-1);}private TreeNode buildTreeChild(int[] preorder, int[] inorder, int inorderbegin, int inorderend) {// 空树if (inorderbegin > inorderend) {return null;}// 创建根结点TreeNode root = new TreeNode(preorder[rootIndex]);// 找到边界int border = findVal(inorder, preorder[rootIndex]);rootIndex++;// 创建左子树root.left = buildTreeChild(preorder, inorder, inorderbegin, border-1);// 创建右子树root.right = buildTreeChild(preorder, inorder, border+1, inorderend);return root;}// 找到根结点在中序遍历中的位置来划分左子树和右子树private int findVal(int[] inorder, int val) {for (int i = 0; i < inorder.length; i++) {if (inorder[i] == val) {return i;}}return -1;}
}

前序学完了,还有后序:

从中序与后序遍历序列构造二叉树

思路:后序遍历同样是确定根结点的位置,从后序遍历数组的末尾开始遍历根节点,在中序遍历中寻找到根结点的位置并划分左右子树。与上述思路类似。

注意:后序遍历是:左子树 右子树 根;而前序遍历是:根 左子树 右子树 。这也就意味着前序遍历找到的根是左子树的根(除祖先节点外) ,即我们先得创建左子树;而后序遍历找到的根是右子树的根(除祖先节点外),即我们先得创建右子树。因为创建二叉树其实就是依赖于根结点,谁于根结点临近创建谁。

class Solution {// 后续遍历找到根结点,再根据根结点确定左子树和右子树private int rootIndex;public TreeNode buildTree(int[] inorder, int[] postorder) {rootIndex = postorder.length-1;return buildTreeChild(inorder, postorder, 0, inorder.length-1);}private TreeNode buildTreeChild(int[] inorder, int[] postorder,int inorderbegin, int inorderend) {if (inorderbegin > inorderend) {return null;}TreeNode root = new TreeNode(postorder[rootIndex]);// 在中序遍历的数组中找到根结点的位置int border = findVal(inorder, postorder[rootIndex]);rootIndex--;root.right = buildTreeChild(inorder, postorder, border+1, inorderend);root.left = buildTreeChild(inorder, postorder, inorderbegin, border-1);return root;}private int findVal(int[] inorder, int val) {for (int i = 0; i < inorder.length; i++) {if (inorder[i] == val) {return i;}}return -1;}
}

二叉树的最近公共祖先

题目: 

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

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

示例 1:

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

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 105] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同 。
  • p != q
  • p 和 q 均存在于给定的二叉树中。

思路一:采用穷举的方法,看看会出现几种情况。

上面三种情况其实就是通过示例总结出来的 

 代码实现:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// 在递归去寻找的过程中可能会出现下面两种情况(限制条件)if (root == null) {return null;}if (root == q || root == p) {return root;}// 走到这里说明根结点一定不存在,则判断左子树和右子树即可// 遍历左子树TreeNode leftTree = lowestCommonAncestor(root.left, p, q);// 遍历右子树TreeNode rightTree = lowestCommonAncestor(root.right, p, q);// 再遍历完成之后,我们就来判断是哪种情况if (leftTree != null && rightTree != null) {return root;}if (leftTree != null && rightTree == null) {return leftTree;}// 下面的代码可以简化为 return rightTree;if (leftTree == null && rightTree != null) {return rightTree;}return null;}
}

如果我们总结不出来,也没关系。还有另外一种方法,就是把p和q出现的路线储存起来,然后再去一 一比较,遇到第一个相等的就是公共的祖先。

首先,得确定是用什么数据结构来储存路线。栈 还是 队列呢?其实都是可以的。因为我们采用的是从上往下遍历,那么根结点一定是最先被放入栈(队列)中的。而我们比较的方式不同,就导致了储存的方式不同。如果我们是想找不同,那就得用队列,从根结点开始比较;如果我们是想找相同,那就得用栈,从p和q开始比较,找到相同的节点。

栈的实现方式:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {Stack<TreeNode> stackP = new Stack<>();Stack<TreeNode> stackQ = new Stack<>();getPath(root, p, stackP);getPath(root, q, stackQ);// 先让长的走差值步数if (stackP.size() > stackQ.size()) {int size = stackP.size() - stackQ.size();while (size-- > 0) {stackP.pop();}} else {int size = stackQ.size() - stackP.size();while (size-- > 0) {stackQ.pop();}}// 开始一起出while (stackQ.peek() != stackP.peek()) {stackQ.pop();stackP.pop();}return stackQ.peek();}private TreeNode getPath(TreeNode root, TreeNode target, Stack<TreeNode> stack) {if (root == null) {return null;}stack.push(root); // 先得把这个入栈if (root == target) {return root;}// 左子树TreeNode leftTree = getPath(root.left, target, stack);if (leftTree != null) { // 左子树不为null,说明在左子树找到了,即返回return leftTree;}// 右子树TreeNode rightTree = getPath(root.right, target, stack);if (rightTree != null) { // 右子树不为null,说明在右子树找到了,即返回return rightTree;}// 左右子树的遍历结果都是null,即都没找到,就出栈if (leftTree == null && rightTree == null) {stack.pop();}return null;}
}

在用队列去写时,我们就会发现一个问题:如果左右子树都为null,那么证明这个节点不是我们路径上的节点,就得出队,但是队列的数据是先进先出的特点,不满足我们的要求,即普通队列是不行的。因此,就只能用栈。

我们在分析问题时,可能刚刚不会遇到这点,但是后面在做题时,体会到了这点就行,不管是什么思路,我们都得上手去写才可以。

根据二叉树创建字符串

题目:

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

示例 1:

输入:root = [1,2,3,4]
输出:"1(2(4))(3)"
解释:初步转化后得到 "1(2(4)())(3()())" ,但省略所有不必要的空括号对后,字符串应该是"1(2(4))(3)" 。

示例 2:

输入:root = [1,2,3,null,4]
输出:"1(2()(4))(3)"
解释:和第一个示例类似,但是无法省略第一个空括号对,否则会破坏输入与输出一一映射的关系。

提示:

  • 树中节点的数目范围是 [1, 104]
  • -1000 <= Node.val <= 1000

思路:根据示例,我们就可以看出:遇到左子树就得添加“(”,当左子树走完,就得添加“)”,当左子树为null,并且右子树不为null时,得添加“()”。 

代码实现:

class Solution {// 通过 StringBuild 来构建字符串private StringBuilder sb = new StringBuilder();public String tree2str(TreeNode root) {dfs(root);return sb.toString();}private void dfs(TreeNode root) {if (root == null) {return;}// 根结点sb.append(root.val);// 根的左子树if (root.left != null) {sb.append("(");// 继续递归去左子树寻找dfs(root.left);// 左子树走完了得加右括号sb.append(")");} else {if (root.right != null) {// 左边添加一对空括号sb.append("()");} else {return;}}// 根的右子树if (root.right != null) {sb.append("(");dfs(root.right);sb.append(")");} else {return;}}
}

总结:通过上面几题的练习,我们不难发现其实有的题目需要我们去利用示例的规律来写,但更多的题目是需要我们对数据结构进行不断的学习和熟练,这样才能更加得心应手。 

好啦!本期 数据结构之初始二叉树(4)的学习之旅就到此结束啦!二叉树的折磨也是暂时的结束啦!即将开启新的数据结构之旅!我们下一期再一起学习吧!

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

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

相关文章

queue的模拟实现【C++】

文章目录 全部的实现代码放在了文章末尾什么是适配器模式&#xff1f;准备工作包含头文件定义命名空间类的成员变量 默认成员函数emptysizefrontbackpushpop全部代码 全部的实现代码放在了文章末尾 queue的模拟实现和stack一样&#xff0c;采用了C适配器模式 queue的适配器一…

Java生成四位纯数字并且确保唯一性

背景&#xff1a; 给了我一个需求&#xff0c;由于某些问题原因&#xff0c;需要给属性和数据添加一个code字段&#xff0c;这是给我发的消息 这两个要求其实是同一个需求&#xff0c;就是在创建对象的时候塞入一个unique的code嘛&#xff0c;听起来很简单吧&#xff0c;但是实…

GooglePlay 金融品类政策更新(7月17号)

距离上次政策大更新&#xff08;4月5号&#xff09;才过去了3个月&#xff0c;Google Play又迎来了一次大更新&#xff0c;不得不说Google Play的要求越来越高了。 我们来梳理一下这次GooglePlay针对金融品类更新了哪些政策: 1.要求提供金融产品和服务的开发者必须注册为组织…

Window环境下MySQL管理

1、MySQL服务启用和停止 图形化界面管理 使用键盘组合键&#xff08;Win R&#xff09;打开运行对话框&#xff0c;在对话框中输入services.msc并点击确定。 这里可以看到服务名称为MySQL84并处于正在运行的状态。 选中后右键可以进行暂停、停止、重启等操作。 命令提示符管理…

OpenCV 直方图概念,直方图均衡化原理详解

文章目录 直方图相关概念颜色灰度级作用应用场景 C 使用OpenCV绘制直方图单通道直方图关键代码分析&#xff1a;calcHist函数分析使用OpenCV API来绘制直方图 效果图&#xff1a; 彩色三通道直方图效果图&#xff1a; 直方图均衡化概念均衡化作用均衡化效果均衡化数学原理步骤数…

Linux中进程间通信--匿名管道和命名管道

本篇将会进入 Linux 进程中进程间通信&#xff0c;本篇简要的介绍了 Linux 中进程为什么需要通信&#xff0c;进程间通信的常用方式。然后详细的介绍了 Linux 进程间的管道通信方式&#xff0c;管道通信分为匿名管道和命名管道&#xff0c;本篇分别介绍了其实现的原理&#xff…

基于VMware(虚拟机) 创建 Ubunton24.04

目录 1.设置 root 密码 2. 防火墙设置 2.1 安装防火墙 2.2 开启和关闭防火墙 2.3 开放端口和服务规则 2.4 关闭端口和删除服务规则 2.5 查看防火墙状态 3. 换源 3.1 源文件位置 3.2 更新软件包 1. 设置网络 1. 在安装ubuntu时设置网络 2.在配置文件中修改 2.设置 r…

17_高级进程间通信 UNIX域套接字1

非命名的UNIX域套接字 第1个参数domain&#xff0c;表示协议族&#xff0c;只能为AF_LOCAL或者AF_UNIX&#xff1b; 第2个参数type&#xff0c;表示类型&#xff0c;只能为0。 第3个参数protocol&#xff0c;表示协议&#xff0c;可以是SOCK_STREAM或者SOCK_DGRAM。用SOCK_STR…

HTTP 缓存

缓存 web缓存是可以自动保存常见的文档副本的HTTP设备&#xff0c;当web请求抵达缓存时&#xff0c;如果本地有已经缓存的副本&#xff0c;就可以从本地存储设备而不是从原始服务器中提取这个文档。使用缓存有如下的优先。 缓存减少了冗余的数据传输缓存环节了网络瓶颈的问题…

MySQL学习之InnoDB引擎,索引

Mysql中的引擎 我们先来看一下MySql提供的有哪些引擎 mysql> show engines; 从上图我们可以查看出 MySQL 当前默认的存储引擎是InnoDB,并且在5.7版本所有的存储引擎中只有 InnoDB 是事务性存储引擎&#xff0c;也就是说只有 InnoDB 支持事务。 查看MySQL当前默认的存储引…

算法力扣刷题记录 五十一【654.最大二叉树】

前言 二叉树篇&#xff0c;继续。 记录 五十一【654.最大二叉树】 一、题目阅读 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。…

套接字编程一(简单的UDP网络程序)

文章目录 一、 理解源IP地址和目的IP地址二、 认识端口号1. 理解 "端口号" 和 "进程ID"2. 理解源端口号和目的端口号 三、 认识协议1. 认识TCP协议2. 认识UDP协议 四、 网络字节序五、 socket编程接口1. socket 常见API2. sockaddr结构&#xff08;1&#…

WebGIS的Web服务概述

WebGIS是互联网技术应用于GIS开发的产物&#xff0c;是现代GIS技术的重要组成部分&#xff0c;其中的Web服务是现代WebGIS的核心技术和重要标志&#xff0c;它集GIS、程序组件和互联网的优点于一身&#xff0c;深刻改变了GIS开发和应用的方式&#xff0c;绕过了本地数据转换和本…

Unity 批处理详讲(含URP)

咱们在项目中&#xff0c;优化性能最重要的一个环节就是合批处理&#xff0c;&#xff0c;在早期Unity中&#xff0c;对于合批的处理手段主要有三种&#xff1a; Static Batching Dynamic Batching GPU Instancing 如今Unity 为了提升合批范围与效率&#xff0c;提供了…

ICT测试原理

目录&#xff1a; 一、什么是ICT 二、ICT在哪使用 三、ICT如何测试 1、隔离(Guarding)原理 2、电容器测试原理 3、电感器测试原理 4、普通二极管测试方法(MODE D) 5、晶体管的测量原理 (三端点)(MODE TR) 6、短/开路的测试原理 1&#xff09;学习短路表 2&#xff…

基于chrome插件的企业应用

一、chrome插件技术介绍 1、chrome插件组件介绍 名称 职责 访问权限 DOM访问情况 popup 弹窗页面。即打开形式是通过点击在浏览器右上方的icon&#xff0c;一个弹窗的形式。 注: 展示维度 browser_action:所有页面 page_action:指定页面 可访问绝大部分api 不可以 bac…

【数据结构】排序算法——Lessen1

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

【动态专修】2024年五菱维修手册和电路图资料更新

经过整理&#xff0c;2017-2024年五菱汽车全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照表…

人、智能、机器人……

在遥远的未来之城&#xff0c;智能时代如同晨曦般照亮了每一个角落&#xff0c;万物互联&#xff0c;机器智能与人类智慧交织成一幅前所未有的图景。这座城市&#xff0c;既是科技的盛宴&#xff0c;也是人性与情感深刻反思的舞台。 寓言&#xff1a;《智光与心影》 在智能之…

Python自动化DevOps任务入门

目录 Python自动化DevOps任务入门 一、环境和工具配置 1. 系统环境与Python版本 2. 虚拟环境搭建 3. 必要的库安装 二、自动化部署 1. 使用Fabric进行流式部署 2. 使用Ansible编写部署剧本 三、持续集成和测试 1. 配置CI/CD工具 选择工具 配置工具 构建和测试自动…