Java数据结构第十五期:走进二叉树的奇妙世界(四)



专栏:Java数据结构秘籍
个人主页:手握风云
目录
一、二叉树OJ练习题(续)
1.1. 二叉树的层序遍历
1.2. 二叉树的最近公共祖先
1.3. 从前序与中序遍历序列构造二叉树
1.4. 从中序与后序遍历序列构造二叉树
1.5. 根据二叉树创建字符串
一、二叉树OJ练习题(续)
1.1. 二叉树的层序遍历
层序遍历,就是从左到右依次访问每个节点。这里我们要借助队列来非递归方式的实现。我们先将根结点root放入队列,再用cur引用来接收弹出的根结点最后再打印。当左右子树不为空时,再一次将左子树和右子树放入队列中。然后先弹出左子树,如果左子树的左右结点不为空,再次放入。当队列为空时,遍历过程结束。所以下面这棵二叉树的打印结果应为“4271369”。



import java.util.LinkedList;
import java.util.Queue;class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right import java.util.LinkedList;
import java.util.Queue;class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public void levelOrder(TreeNode root){Queue<TreeNode> queue = new LinkedList<TreeNode>();queue.offer(root);while(! queue.isEmpty()){TreeNode cur = queue.poll();System.out.print(cur.val+" ");if(cur.left != null){queue.offer(cur.left);}if(cur.right != null){queue.offer(cur.right);}}}
}= right;}
}public class Solution {public void levelOrder(TreeNode root){Queue<TreeNode> queue = new LinkedList<TreeNode>();queue.offer(root);while(! queue.isEmpty()){TreeNode cur = queue.poll();System.out.print(cur.val+" ");if(cur.left != null){queue.offer(cur.left);}if(cur.right != null){queue.offer(cur.right);}}}
}
public class Test {public static void main(String[] args) {TreeNode root = new TreeNode(4,new TreeNode(2),new TreeNode(7));root.left.left = new TreeNode(1);root.left.right = new TreeNode(3);root.right.left = new TreeNode(6);root.right.right = new TreeNode(9);Solution solution = new Solution();solution.levelOrder(root);}
}
但题目当中给出的类型是嵌套List<List<Integer>>,同时根据输出的格式来,创建一个二维数组,第一层放入第一列中。我们依然可以借助上面的队列来实现。与上面的方法类似,我们还需要再定义一个整型size变量来接受队列的长度,根据队列的长度来选择弹出与进入的操作。

public List<List<Integer>> levelOrder1(TreeNode root){List<List<Integer>> ret = new ArrayList<>();if(root == null) return ret;Queue<TreeNode> queue1 = new LinkedList<TreeNode>();queue1.offer(root);while(! queue1.isEmpty()){List<Integer> curList = new ArrayList<>();int size = queue1.size();while(size != 0){TreeNode cur = queue1.poll();curList.add(cur.val);if(cur.left != null){queue1.offer(cur.left);}if(cur.right != null){queue1.offer(cur.right);}size--;}ret.add(curList);}return ret;}
import java.util.List;public class Test {public static void main(String[] args) {Solution solution = new Solution();TreeNode root = new TreeNode(4,new TreeNode(2),new TreeNode(7));root.left.left = new TreeNode(1);root.left.right = new TreeNode(3);root.right.left = new TreeNode(6);root.right.right = new TreeNode(9);solution.levelOrder(root);List<List<Integer>> result = solution.levelOrder1(root);System.out.println(result);}
}
1.2. 二叉树的最近公共祖先

如果是上图中第三种情况,那么我们就直接返回root。如果是第一种情况,当root向下遍历时,遇到p、q结点时,直接返回到root(如下图所示)。

如果是第二种情况,当root遍历到p节点时,5结点返回p的地址,同时我们也可以找到q结点并返回。但还是有一种极端情况,q是孩子节点p的一个子结点。按照上面的思路,直接就返回这个结点。所以这种极端情况可以总结为,只要root遍历到p或者q中一个,直接返回对应的结点。因为p、q都在同一棵子树上,当root去遍历另一棵子树时,会返回null,所以最终结果是p,与p或q在根节点上是类似的。


完整代码实现:
class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){if(root == null){return root;}if(root == p || root == q){return root;}TreeNode leftT = lowestCommonAncestor(root.left,p,q);TreeNode rightT = lowestCommonAncestor(root.right,p,q);if(leftT != null && rightT != null){//p、q分别在左右子树上return root;}else if(leftT != null){return leftT;} else if (rightT != null) {return rightT;}return null;}
}
public class Test {public static void main(String[] args) {TreeNode root = new TreeNode(3,new TreeNode(5),new TreeNode(1));root.left.left = new TreeNode(6);root.left.right = new TreeNode(2,new TreeNode(7),new TreeNode(4));root.right.left = new TreeNode(0);root.right.right = new TreeNode(8);TreeNode p = root.left;TreeNode q = root.right;Solution solution = new Solution();TreeNode cur = solution.lowestCommonAncestor(root,p,q);System.out.println(cur.val);}
}
这道题还有另一种做法:如果我们把二叉树里的每一个结点新增加一个前驱域,用来存储父节点的地址,那么这道题的思路就变成了一链表交点的形式来求最近的公共祖先结点。可是定义的TreeNode类里面的成员变量里面没有这个变量。此时可以利用两个栈来存储从root到p、q结点路径上的结点。
基本思路:只要root不为空,就把结点扔进栈当中。让长度较大的栈先弹出一定的元素,使得两个栈长度相等。两个栈再同时弹出元素,判断两个值是否相等,相等则是最近的公共祖先结点。

而下面问题又来了,我们该如何求路径上的结点?只要root不等于p或者q,就将该节点放进栈中并继续递归;当root等于p或者q时,就停止。如果在遍历过程中某一个结点既不等于p、q,且左右都为空,那么这个元素就会被弹出。
完整代码实现:
import java.util.Stack;class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack){if(root == null){return false;}stack.push(root);if(root == node){return true;}boolean flag = getPath(root.left,node,stack);if(flag){return true;}flag = getPath(root.right,node,stack);if(flag){return true;}stack.pop();return false;}public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){if(root == null){return null;}Stack<TreeNode> stack1 = new Stack<>();Stack<TreeNode> stack2 = new Stack<>();getPath(root,p,stack1);getPath(root,q,stack2);int len1 = stack1.size();int len2 = stack2.size();int len = len1 - len2;if(len < 0){len = Math.abs(len);while(len != 0){stack2.pop();len--;}}else{while(len != 0){stack1.pop();len--;}}//保证两个栈的长度一样while (!stack1.isEmpty() && !stack2.isEmpty()){if(stack1.peek() == stack2.peek()){return stack1.pop();}else{stack1.pop();stack2.pop();}}return null;}
}
public class Test {public static void main(String[] args) {TreeNode root = new TreeNode(3,new TreeNode(5),new TreeNode(1));root.left.left = new TreeNode(6);root.left.right = new TreeNode(2,new TreeNode(7),new TreeNode(4));root.right.left = new TreeNode(0);root.right.right = new TreeNode(8);TreeNode p = root.left;TreeNode q = root.right;Solution solution = new Solution();TreeNode cur = solution.lowestCommonAncestor(root,p,q);System.out.println(cur.val);}
}
1.3. 从前序与中序遍历序列构造二叉树
基本思路:1.遍历前序遍历的数组,遇到元素之后,在中序遍历数组当中找到该数字;2.该数字的左边就是左树,右边就是右树。上述两步构成一个递归来构造子树。

我们以中序遍历的数组的第一个元素ibegin,最后一个元素iend之间找到二叉树的根,因为是前序遍历,先有的左树再有的右树,那么左边的区间就会是(9,x) = (ibegin,iend),iend = iroot-1;相反我们去递归右树,ibegin=iroot+1。也就是说,递归根结点创建左树和右树时,还需要知道ibegin和iend的范围。
我们还需要额外创建一个方法来接受ibegin和iend的参数。创建root,利用buildTreeChild方法递归来创建根结点的左树和右树。可我们不知道中序遍历的数组中根结点的下标,还需要一个方法来查找根结点的下标。
public class Solution {public TreeNode buildTree(int[] preorder, int[] inorder){return buildTreeChild(preorder,0,inorder,0, inorder.length-1);}public TreeNode buildTreeChild(int[] preorder, int prevIndex,int[] inorder, int inbegin, int inend){TreeNode root = new TreeNode(preorder[prevIndex]);int rootIndex = findIndex(inorder,inbegin,inend,preorder[prevIndex]);prevIndex++;root.left = buildTreeChild(preorder,prevIndex,inorder,inbegin,rootIndex-1);root.right = buildTreeChild(preorder,prevIndex,inorder,rootIndex-1,inend);return root;}private int findIndex(int[] inorder,int inbegin,int inend,int key) {for(int i = inbegin; i <= inend; i++) {if(inorder[i] == key) {return i;}}return -1;}
}
但此时的代码还是有一点逻辑上的问题,就是递归结束的条件是什么?一棵二叉树,总有一棵子树的左右子树都为空。但我们上面的代码没有null。所以要处理一下边界情况:
if(inbegin > inend){return null;
}
还存在另一个问题,就是局部变量的定义。因为二叉树遍历完左树的时候,最后给根返回0,从0再去遍历右子树。所以我们把prevIndex定义为成员变量。
完整代码实现:
class TreeNode{int val;TreeNode left;TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public int prevIndex;public TreeNode buildTree(int[] preorder, int[] inorder){return buildTreeChild(preorder,inorder,0, inorder.length-1);}public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend){if(inbegin > inend){return null;}TreeNode root = new TreeNode(preorder[prevIndex]);int rootIndex = findIndex(inorder,inbegin,inend,preorder[prevIndex]);prevIndex++;root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);return root;}private int findIndex(int[] inorder,int inbegin,int inend,int key) {for(int i = inbegin; i <= inend; i++) {if(inorder[i] == key) {return i;}}return -1;}
}
public class Test {public static void PrintTreeNode(TreeNode root){if(root == null){return;}System.out.print(root.val+" ");PrintTreeNode(root.left);PrintTreeNode(root.right);}public static void main(String[] args) {Solution soluion = new Solution();int[] preOrder = new int[]{3,9,20,15,7};int[] inOrder = new int[]{9,3,15,20,7};TreeNode root = soluion.buildTree(preOrder,inOrder);PrintTreeNode(root);}
}
1.4. 从中序与后序遍历序列构造二叉树
与上面一题的思路一样,但后序遍历的顺序是“左子树、右子树、根”,那根结点从后面开始找。并且在创建树的过程中,要先创建右树再创建左树。
class TreeNode{int val;TreeNode left;TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public int postIndex = 0;public TreeNode buildTree(int[] inorder, int[] postorder){postIndex = postorder.length-1;return buildTreeChild(postorder,inorder,0, inorder.length-1);}public TreeNode buildTreeChild(int[] preorder, int[] inorder, int inbegin, int inend){if(inbegin > inend){return null;}TreeNode root = new TreeNode(preorder[postIndex]);int rootIndex = findIndex(inorder,inbegin,inend,preorder[postIndex]);postIndex--;root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);return root;}private int findIndex(int[] inorder,int inbegin,int inend,int key) {for(int i = inbegin; i <= inend; i++) {if(inorder[i] == key) {return i;}}return -1;}
}
public class Test {public static void PrintTreeNode(TreeNode root){if(root == null){return;}PrintTreeNode(root.left);PrintTreeNode(root.right);System.out.print(root.val+" ");}public static void main(String[] args) {Solution solution = new Solution();int[] Inorder = new int[]{9,3,15,20,7};int[] Postorder = new int[]{9,15,7,20,3};TreeNode root = solution.buildTree(Inorder,Postorder);PrintTreeNode(root);}
}
1.5. 根据二叉树创建字符串

通过上图分析:当1的左子树不为空,就用一个(,2的左子树也不为空,也使用一个(,4再往下递归返回null,直接)闭合;2的右子树为null,返回);1的右子树不为空,返回(,3递归返回null,直接)闭合。
所以我们可以总结下来规律:当子树不为空时,直接加左括号;当root的左树为空,且右树也为空,直接加右括号闭合;当root的左树不为空,右树为空,也加右括号闭合。
public void tree2strChild(TreeNode root,StringBuilder stringBuilder){if(root == null){return;}stringBuilder.append(root.val);//判断根的左子树if(root.left != null){stringBuilder.append("(");tree2strChild(root.left,stringBuilder);//递归左树stringBuilder.append(")");//左树走完,右括号闭合}else {if(root.right == null){return;//因为4结点走完,返回2结点,这里本身就会加一个")"}else {}}//判断根的右子树if(root.right != null){stringBuilder.append("(");tree2strChild(root.right,stringBuilder);stringBuilder.append(")");}else {}}
但也存在另一种情况:如果子树的左边为空,右边不为空,就直接加一对小括号,再去递归右树,把4再加进去。再继续往下走,如果root.right为空,正好符合上面2结点的情况:2的左边走完,右边为空,直接return加右括号。所以只要左树为空,右树不为空,就不做任何处理。

完整代码实现:
class TreeNode{public int val;public TreeNode left;public TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}public class Solution {public String tree2str(TreeNode root){StringBuilder stringBuilder = new StringBuilder();tree2strChild(root,stringBuilder);return stringBuilder.toString();}public void tree2strChild(TreeNode root,StringBuilder stringBuilder){if(root == null){return;}stringBuilder.append(root.val);//判断根的左子树if(root.left != null){stringBuilder.append("(");tree2strChild(root.left,stringBuilder);//递归左树stringBuilder.append(")");//左树走完,右括号闭合}else {if(root.right == null){return;//因为4结点走完,返回2结点,这里本身就会加一个")"}else {stringBuilder.append("()");}}//判断根的右子树if(root.right != null){stringBuilder.append("(");tree2strChild(root.right,stringBuilder);stringBuilder.append(")");}else {return;}}
}
public class Test {public static void main(String[] args) {Solution solution = new Solution();TreeNode root1 = new TreeNode(1,new TreeNode(2),new TreeNode(3));root1.left.left = new TreeNode(4);TreeNode root2 = new TreeNode(1,new TreeNode(2),new TreeNode(3));root2.left.right = new TreeNode(4);System.out.println(solution.tree2str(root1));System.out.println(solution.tree2str(root2));}
}相关文章:
Java数据结构第十五期:走进二叉树的奇妙世界(四)
专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、二叉树OJ练习题(续) 1.1. 二叉树的层序遍历 1.2. 二叉树的最近公共祖先 1.3. 从前序与中序遍历序列构造二叉树 1.4. 从中序与后序遍历序列构造二叉树 1.5. 根据二叉树创建…...
【MySQL】CAST()在MySQL中的用法以及其他常用的数据类型转换函数
1. cast() CAST() 在 MySQL 中用于将一个表达式的类型转换为另一个类型。这在处理不同类型的数据时非常有用,比如将字符串转换为数字,或者将浮点数转换为整数等。 1.1 CAST() 函数的基本语法 CAST() 函数的基本语法如下: CAST(expression…...
使用Truffle、Ganache、MetaMask、Vue+Web3完成的一个简单区块链项目
文章目录 概要初始化Truffle项目创建编写合约编译合约配置Ganache修改truffle-config.js文件编写迁移文件部署合约使用Truffle 控制台使用MetaMask和VueWeb3与链交互 概要 使用Truffle、Ganache、MetaMask、VueWeb3完成的一个简单区块链项目。 初始化Truffle项目 安装好truf…...
初出茅庐的小李博客之按键驱动库使用
驱动库介绍 源码地址:https://github.com/jiejieTop/ButtonDrive 使用只需3步,创建按键,按键事件与回调处理函数链接映射,周期检查按键,支持单双击、连按、长按;采用回调处理按键事件(自定义消…...
如何调试Linux内核?
通过创建一个最小的根文件系统,并使用QEMU和GDB进行调试。 1.准备工作环境 确保系统上安装了所有必要的工具和依赖项。 sudo apt-get update //更新一下软件包 sudo apt-get install build-essential git libncurses-dev bison flex libssl-dev qemu-system-x…...
ECharts组件封装教程:Vue3中的实践与探索
在日常的前端开发中,ECharts 作为一款强大且易用的图表库,被广泛应用于数据可视化场景。为了更好地在 Vue3 项目中复用 ECharts 功能,我们可以将其封装成一个组件。本文将带大家一步步实现 ECharts 的 Vue3 组件封装,并演示如何在父组件中调用和使用。 一、封装 ECharts 组…...
NAT 代理服务 内网穿透
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 NAT 技术背景二:🔥 NAT IP 转换过程三:🔥 NAPT四:🔥 代理服务器🦋 正向…...
CAN硬件协议详解
一、基本理论: 1、CAN的总线结构: CAN总线 网络结构 有 闭环和开环 两种形式;无论实际的网络多复杂,都离不开这两种基本结构。 闭环结构的CAN总线网络,总线的两端各并联一个120Ω的电阻,两…...
网络安全等级保护:网络安全等级保护基本技术
下面我们概括性探讨一下等级保护用到的一些技术,有关这些技术的每一个方面的每一个部分都可以是一部大块头,甚至一部大块头都无法介绍清楚,需要系列性的书籍去展开,所以这里也只能做到抛砖而已。期望起到抛砖引玉的作用࿰…...
信刻光盘安全隔离与信息交换系统让“数据摆渡”安全高效
随着数据传输、存储及信息技术的飞速发展,信息安全保护已成为重中之重。各安全领域对跨网数据交互的需求日益迫切,数据传输的安全可靠性成为不可忽视的关键。为满足业务需求并遵守保密规范,针对于涉及重要秘密信息,需做到安全的物…...
数据结构课程设计(java实现)---九宫格游戏,也称幻方
【问题描述】 九宫格,一款数字游戏,起源于河图洛书,与洛书是中国古代流传下来的两幅神秘图案,历来被认为是河洛文化的滥觞,中华文明的源头,被誉为"宇宙魔方"。九宫格游戏对人们的思维锻炼有着极大…...
[思考记录]AI时代下,悄然的改变
尝试用 xAI-Grok 去了解DS开源周的信息,有那么点被Grok的输出惊艳到。“请你以技术编辑的角色,重点参考官方文档,介绍DeepSeek开源周的内容,写一篇技术分享文章。”,得到的文字看起来很是舒服,内容靠谱、结…...
JAVA笔记【一】
现实 (抽象) 类 (创建) 对象 特点: 1.面向对象 2.跨平台 3.安全性 4.多线程 java程序基本结构 1. java源代码文件实际是普通的文本文件,源代码文件必须是.java扩展名,且必须小写 2. …...
[Java基础] 常用注解
文章目录 1. 元注解2. 非元注解2.1 常用JDK自带注解2.2 常用Spring相关注解2.2.1 在Spring框架中,注解用于简化配置和增强代码的可读性。以下是常用的Spring注解的一部分2.2.2 针对controller的相关注解2.2.3 AOP相关注解2.2.4 Enable系列注解 2.3 常用Lombok注解 1…...
uvm中的run_test作用
在SystemVerilog和UVM验证环境中,run_test() 是启动UVM仿真流程的核心函数。它负责初始化UVM框架、创建测试用例实例,并触发UVM的Phase机制来执行验证环境的构建和运行 1. run_test() 的作用 run_test() 是UVM提供的内置函数,定义在UVM库中…...
brew search报错,xcrun:error:invalid active developer path CommandLineTools
问题出现的原因 出现“xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun”错误,通常是因为Xcode命令行工具未正确安装或其路径已损坏。以下是几种常见的…...
C#内置委托(Action)(Func)
概述 在 C# 中,委托是一种类型,它表示对具有特定参数列表和返回类型的方法的引用。C# 提供了一些内置委托,使得开发者可以更方便地使用委托功能,无需手动定义委托类型。本文将详细介绍 Action 和 Func 这两个常用的内置委托。 A…...
kubernetes 部署项目
随着容器化技术的发展,使用Kubernetes(简称K8s)来部署和管理应用已经成为现代软件开发的标准实践之一。Kubernetes提供了一套强大的工具集,使得部署、扩展和管理应用程序变得更为简便高效。本文将带你走过从准备环境到部署一个实际…...
《几何原本》命题I.2
《几何原本》命题I.2 从一个给定的点可以引一条线段等于已知的线段。 设 A A A 为给定点, B C BC BC 为给定线段 连接 A B AB AB,作等边 △ A B D \triangle ABD △ABD 以 B B B 为圆心, B C BC BC 为半径作小圆 延长 D B DB DB 交小圆…...
【我的 PWN 学习手札】House of Kiwi
House of Kiwi 之前我们利用IO_FILE一般是通过劫持vtable来实现的, House of Kiwi虽然不是通过劫持vtable来实现,但实质上是劫持vtable指向的全局的_IO_file_jumps_表来实现的。注意:对于某些版本的glibc,_IO_file_jumps_并不可写…...
案发现场时空回溯:UWB无法全域留痕,无感定位全链路可复盘
案发现场时空回溯:UWB无法全域留痕,无感定位全链路可复盘镜像视界浙江科技有限公司,作为数字孪生、视频孪生领域底层原创技术核心供给方,依托国家十四五重点课题专项研究、镜像视界浙江普陀时空大数据应用技术联合研究院深度产学研…...
FlashAttention的OOM排查:为什么显存够了还是报内存不足?
之前有个团队在昇腾NPU上跑Llama-2-7B,模型是FP16权重,seq_len4096。他们算了算显存:模型权重13.5GB 激活值4GB KV Cache 4GB 21.5GB,昇腾910有32GB显存,绰绰有余。 结果一跑就报OOM(Out Of Memory&…...
瑞数6代JSVMP逆向实战:Node.js复现可信字节码运行时
1. 这不是“绕过验证码”,而是和瑞数6代打一场精密的JavaScript攻防战你肯定见过那个页面:刚点开目标网站,还没输入账号,浏览器就卡住半秒,接着弹出一个412 Precondition Failed——不是403,不是500&#x…...
85%企业将淘汰纯业务程序员!2026年前,大模型才是你的职业救命稻草!
文章指出传统技术岗面临淘汰风险,85%企业计划在2026年前淘汰纯业务型程序员。未来职场核心竞争力在于掌握大模型技术。文章强调大模型技术是技术人的时代红利,提供从入门到精通的全套视频教程,涵盖提示词工程、RAG、Agent等技术点。文章还分析…...
在Taotoken模型广场根据任务需求挑选合适模型的实践
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在Taotoken模型广场根据任务需求挑选合适模型的实践 1. 模型广场:你的模型选型起点 当你开始一个新项目,或…...
深度学习的缺失数据革命:使用MIDAS实现高效多重插补
深度学习的缺失数据革命:使用MIDAS实现高效多重插补 【免费下载链接】MIDAS Multiple imputation utilising denoising autoencoder for approximate Bayesian inference 项目地址: https://gitcode.com/gh_mirrors/midas3/MIDAS 在数据科学和机器学习领域&a…...
面试官问我SQL怎么调优,我直接甩出这套Explain对比法
面试官问我SQL怎么调优,我直接甩出这套Explain对比法 线上系统突然变慢,用户投诉纷至沓来,运维群里消息炸了锅。排查半天,发现罪魁祸首竟然是一条不起眼的SQL语句。这条SQL在测试环境跑得飞快,一到生产环境就像老牛拉破车。相信很多开发者都遇到过这种场景——SQL写的时候…...
STM32新手必看:用CubeMX图形化配置PLL时钟,5分钟搞定72MHz系统时钟
STM32CubeMX图形化配置PLL时钟实战指南 对于刚接触STM32开发的工程师来说,时钟树配置往往是最令人头疼的环节之一。传统的手动寄存器配置方式需要查阅大量参考手册,理解复杂的时钟路径和分频系数关系。而STM32CubeMX这款图形化工具的出现,彻底…...
关于fiddler报错“The system proxy was changed. click to reenable capturing”的解决办法
背景:第一次下载安装fiddler,安装过程没有任何问题,但启动即报错 参考了很多帖子,一个一个排查后,发现是sslvpn的问题(因为访问校园网需要安装了 EasyConnect 深信服SSLVPN客户端),把…...
CANN-昇腾NPU-多机多卡-怎么把16卡用出32卡的效果
16 张 Atlas 800I A2 的理论算力是 16 310 4960 TFLOPS(fp16)。但实际训练 Llama2-7B 只用到了 3200 TFLOPS——利用率 64%。这篇讲怎么把利用率从 64% 提到 85%,等效 16 卡用出 25 卡的效果。 利用率低的原因 理论算力: 16 310 4960 TFL…...
