Leetcode刷题笔记——DFS篇

Leetcode刷题笔记——DFS篇

一、二叉树DFS的相关应用

第一题:括号生成

Leetcode22:括号生成:中等题 (详情点击链接见原题)

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的括号组合

本质就是一个二叉树,,二叉树的每个节点即一种括号组合,分别递归的加入左括号

python代码解法1:方便更直观的看到回溯的过程

class Solution:def dfs(self, n, left, right, path, result):if len(path) == 2 * n:      # 递归出口result.append("".join(path[:]))if left < n:path.append('(')self.dfs(n, left + 1, right, path, result)path.pop(-1)if right < left:path.append(')')self.dfs(n, left, right + 1, path, result)path.pop(-1)def generateParenthesis(self, n: int) -> List[str]:path, result = [], []self.dfs(n, 0, 0, path, result)return result

python代码解法2:简单写法

class Solution:def dfs(self, n, path, res, left, right):if left > n or right > n or right > left:returnif len(path) == 2 * n:res.append(path)returnself.dfs(n, path + '(', res, left + 1, right)self.dfs(n, path + ')', res, left, right + 1)def generateParenthesis(self, n: int) -> List[str]:path, res = '', []self.dfs(n, path, res, 0, 0)return res

第二题:字母大小写全排列

Leetcode784:字母大小写全排列:中等题 (详情点击链接见原题)

给定一个字符串 s ,通过将字符串 s 中的每个字母转变大小写,我们可以获得一个新的字符串。
返回 所有可能得到的字符串集合 。以 任意顺序返回输出

python代码解法1:

class Solution:def backtracking(self, s, index, result):result.append("".join(s))for i in range(index, len(s)):if s[i].isdigit():continueif s[i].isalpha():if s[i].islower():s[i] = chr(ord(s[i]) - 32)self.backtracking(s, i + 1, result)s[i] = chr(ord(s[i]) + 32)else:s[i] = chr(ord(s[i]) + 32)self.backtracking(s, i + 1, result)s[i] = chr(ord(s[i]) - 32)def letterCasePermutation(self, s: str) -> List[str]:result = []s1 = list(s)self.backtracking(s1, 0, result)return result

python代码解法2:

class Solution:def dfs(self, s, index, path, res):if index == len(s):res.append(path)returnself.dfs(s, index + 1, path + s[index], res)if s[index].isalpha():if s[index].islower():self.dfs(s, index + 1, path + chr(ord(s[index]) - 32), res)else:self.dfs(s, index + 1, path + chr(ord(s[index]) + 32), res)def letterCasePermutation(self, s: str) -> List[str]:path, res = "", []st = list(s)self.dfs(st, 0, path, res)return res

第三题:为运算表达式设计优先级

Leetcode241. 为运算表达式设计优先级:中等题 (详情点击链接见原题)

给你一个由数字和运算符组成的字符串 expression ,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果

解题思路
对于一个形如 x op yop为运算符,xy 为操作数】的算式而言,它的结果组合取决于xy 的结果组合数,而 xy又可以递归的看成x op y的算式,该问题的子问题就是 x op y 中的 xy:以运算符分隔的左右两侧算式解

  1. 分解:按运算符分成左右两部分,分别求解
  2. 解决:实现一个递归函数,输入算式,返回算式解
  3. 合并:根据运算符合并左右两部分的解,得出最终解

python代码解法:

class Solution:def diffWaysToCompute(self, expression: str) -> List[int]:if expression.isdigit():   # 1. 如果只有数字,直接返回return [int(expression)]res = []for i, char in enumerate(expression):# 1.分解:遇到运算符,计算左右两侧的结果集# 2.解决:diffWaysToCoumpute 递归函数求出子问题的解left = self.diffWaysToCompute(expression[:i])right = self.diffWaysToCompute(expression[i + 1:])# 3.合并:根据运算符合并子问题的解for l in left:for r in right:if char == '+':res.append(l + r)elif char == '-':res.append(l - r)else:res.append(l * r)return res

第四题:员工的重要性

Letcode690. 员工的重要性:中等题 (详情点击链接见原题)

给定一个保存员工信息的数据结构,它包含了员工 唯一的 id ,重要度 和 直系下属的 id

解题思路
所有员工形成多叉树的结构,每个员工对应多叉树中的一个节点,每个节点包含【员工编号、重要度、直系下属的编号】,一个员工的直系下属对应多叉树中的一个结点的子结点

  1. 对于给定的整数 id,计算以该整数编号对应的员工为根节点的子树中的所有结点的员工重要度之和
  2. 首先遍历数组 employees 并使用哈希表记录 {员工id: 对应 id 的员工信息}
  3. 定位到 整数id对应的员工,计算以该员工为根节点的子树中所有结点的员工重要度之和

python代码解法:

class Solution:def dfs(self, employees_dict, employee_id):if not employees_dict[employee_id].subordinates:  # 递归出口:当某员工没有直系下属时,返回自身的重要度return employees_dict[employee_id].importancetotal = employees_dict[employee_id].importance   # total变量存储员工重要度之和:初始化为当前遍历员工的重要度for emp_id in employees_dict[employee_id].subordinates:	# 如果当前员工有直系下属,则定位到当前员工的每个直系下属,继续DFStotal += self.dfs(employees_dict, emp_id)   # 将遍历到的每个员工的重要度加到重要度之和return totaldef getImportance(self, employees: List['Employee'], id: int) -> int:employees_dict = {}for employee in employees:employees_dict[employee.id] = employeereturn self.dfs(employees_dict, id)

二、网格(岛屿)问题中的DFS

岛屿问题是一类典型的网格问题,每个格子中的数字可能是 0 或者 1。我们把数字为 0 的格子看成海洋格子,数字为 1 的格子看成陆地格子,这样相邻的陆地格子就连接成一个岛屿,在这样一个设定下,就出现了各种岛屿问题的变种,包括岛屿的数量、面积、周长等。不过这些问题,基本都可以用 DFS 遍历来解决

在二叉树的 DFS 中有两个要素:「访问相邻结点」和「判断 base case
访问相邻结点
二叉树本身就是一个递归定义的结构:一棵二叉树,它的左子树和右子树也是一棵二叉树。那么我们的 DFS 遍历只需要递归调用左子树和右子树即可
网格结构中的格子有多少相邻结点?。对于格子 (r, c) 来说(rc 分别代表行坐标和列坐标),四个相邻的格子分别是 (r-1, c)、(r+1, c)、(r, c-1)、(r, c+1)。换句话说,网格结构是「四叉」的。

判断 base case
二叉树遍历的 base caseroot == null
网格遍历的 base case 是 判断当前网格的坐标是否超出网格范围,超出则无需遍历

网格结构 DFS如何避免重复遍历
网格结构的 DFS 与二叉树的 DFS 最大的不同之处在于,遍历中可能遇到遍历过的结点,我们可以把每个格子看成图中的结点,每个结点有向上下左右的四条边。在图中遍历时,自然可能遇到重复遍历结点,这时候 DFS 可能会不停地「兜圈子」,永远停不下来,解决方案是:标记已经遍历过的格子

第一题:岛屿数量

Leetcode200:岛屿数量:中等题 (详情点击链接见原题)

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围

python代码解法:

class Solution:def dfs(self, grid, x, y):if not (0 <= x < len(grid) and 0 <= y < len(grid[0])) or grid[x][y] != "1":returngrid[x][y] = "2"  # 标记为已访问self.dfs(grid, x - 1, y)self.dfs(grid, x + 1, y)self.dfs(grid, x, y - 1)self.dfs(grid, x, y + 1)def numIslands(self, grid: List[List[str]]) -> int:island_num = 0row, col = len(grid), len(grid[0])for x in range(row):for y in range(col):    # 1. 循环遍历网格中的所有节点if grid[x][y] == "1":island_num += 1   # 2. DFS遍历的次数即网格中岛屿的数量self.dfs(grid, x, y)return island_num

第二题:岛屿的周长

Leetcode463:岛屿的周长:简单题 (详情点击链接见原题)

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域

python代码解法:

class Solution:def dfs_perimeter(self, x, y, grid):if not (0 <= x < len(grid) and 0 <= y < len(grid[0])):  # 1.函数因坐标(x, y)超出边界范围,返回一条边return 1if grid[x][y] == 2:  # 2.函数因当前格子是已遍历的陆地格子,和周长没关系,返回0return 0if grid[x][y] != 1:  # 3. 函数因当前格子是海洋格子,返回一条边return 1grid[x][y] = 2return (self.dfs_perimeter(x + 1, y, grid) + self.dfs_perimeter(x - 1, y, grid) +self.dfs_perimeter(x, y + 1, grid) + self.dfs_perimeter(x, y - 1, grid))def islandPerimeter(self, grid: List[List[int]]) -> int:row, col = len(grid), len(grid[0])for x in range(row):for y in range(col):if grid[x][y] == 1:return self.dfs_perimeter(x, y, grid)

第三题:岛屿的最大面积

Leetcode695:岛屿的最大面积:中等题 (详情点击链接见原题)

给你一个大小为 m x n 的二进制矩阵 grid
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着

python代码解法:

class Solution:def dfs_count(self, x, y, grid, island_area):row, col = len(grid), len(grid[0])if x < 0 or x >= row or y < 0 or y >= col:return 0if grid[x][y] != 1:return 0island_area = 1grid[x][y] = 2island_area += self.dfs_count(x + 1, y, grid, island_area)island_area += self.dfs_count(x - 1, y, grid, island_area)island_area += self.dfs_count(x, y + 1, grid, island_area)island_area += self.dfs_count(x, y - 1, grid, island_area)return island_areadef maxAreaOfIsland(self, grid: List[List[int]]) -> int:island_max_area = 0row, col = len(grid), len(grid[0])for x in range(row):for y in range(col):island_area = 0if grid[x][y] == 1:island_area += self.dfs_count(x, y, grid, island_area)island_max_area = max(island_max_area, island_area)return island_max_area

python代码解法(优化后):

class Solution:def dfs(self, grid, x, y):if not (0 <= x < len(grid) and 0 <= y < len(grid[0])) or grid[x][y] != 1:return 0grid[x][y] = 2   # 标记为已访问return 1 + self.dfs(grid, x + 1, y) + self.dfs(grid, x - 1, y) + self.dfs(grid, x, y - 1) + self.dfs(grid, x, y + 1)def maxAreaOfIsland(self, grid: List[List[int]]) -> int:island_max_area = 0row, col = len(grid), len(grid[0])for x in range(row):for y in range(col):island_area = 0if grid[x][y] == 1:island_area += self.dfs(grid, x, y)island_max_area = max(island_max_area, island_area)return island_max_area

第四题:最大人工岛(待补充)

Leetcode827. 最大人工岛:困难题 (详情点击链接见原题)

给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1
返回执行此操作后,grid 中最大的岛屿面积是多少?

第五题:衣橱整理

Leetcode:衣橱整理:中等题 (详情点击链接见原题)

家居整理师将待整理衣橱划分为 m x n 的二维矩阵 grid,其中 grid[i][j] 代表一个需要整理的格子。整理师自 grid[0][0] 开始 逐行逐列 地整理每个格子

python代码解法:

class Solution:def BitSum(self, num):res = 0while num > 0:bit = num % 10res += bitnum //= 10return resdef dfs(self, grid, x, y, cnt):if not (0 <= x < len(grid) and 0 <= y < len(grid[0]) and self.BitSum(x) + self.BitSum(y) <= cnt and grid[x][y] == 0):return 0grid[x][y] = 2return 1 + self.dfs(grid, x - 1, y, cnt) + self.dfs(grid, x + 1, y, cnt) + self.dfs(grid, x, y - 1, cnt) + self.dfs(grid, x, y + 1, cnt)def wardrobeFinishing(self, m: int, n: int, cnt: int) -> int:grid = [[0 for _ in range(n)] for _ in range(m)]count = self.dfs(grid, 0, 0, cnt)return count

第六题:单词搜索

Leetcode79:单词搜索:中等题 (详情点击链接见原题)

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回false

仔细观察即可发现该题与我们上文中的Leetcode112:路径总和的解题思路有点类似

解题思路

  1. 确定递归函数和的参数和返回值
  2. 确定终止条件:当找到最终结果即 index == len(word) - 1就要返回
  3. 确定单层递归测逻辑:当搜索范围超出网格边界或者是已访问过的节点,或者是当前访问的节点不等于单词中对应的字符,则应立即返回

python代码解法:

class Solution:def dfs(self, board, x, y, visited, word, index):if not (0 <= x < len(board) and 0 <= y < len(board[0])):returnif visited[x][y] or board[x][y] != word[index]:  # 当前节点已访问或和word对应的字符不匹配returnif index == len(word) - 1:  # 当索引等于word的长度-1说明所有字符均匹配return Truevisited[x][y] = True   # 标记为已访问if self.dfs(board, x - 1, y, visited, word, index + 1):return Trueif self.dfs(board, x + 1, y, visited, word, index + 1):return Trueif self.dfs(board, x, y - 1, visited, word, index + 1):return Trueif self.dfs(board, x, y + 1, visited, word, index + 1):return Truevisited[x][y] = False   # 回溯,清除访问标识def exist(self, board: List[List[str]], word: str) -> bool:row, col = len(board), len(board[0])visited = [[False for _ in range(col)] for _ in range(row)]for r in range(row):for c in range(col):if board[r][c] == word[0]:if self.dfs(board, r, c, visited, word, 0):return Truereturn False

第八题:串联字符串的最大长度

Leetcode1239. 串联字符串的最大长度:中等题 (详情点击链接见原题)

给定一个字符串数组 arr,字符串 s 是将 arr 的含有 不同字母 的 子序列 字符串 连接 所得的字符串

三、记忆化递归

第一题:单词拆分

Leetcdoe139. 单词拆分:中等题 (详情点击链接见原题)

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

python代码解法:

class Solution:def backtracking(self, s: str, wordSet: set[str], memory, startIndex: int) -> bool:# 边界情况:已经遍历到字符串末尾,返回Trueif startIndex >= len(s):return Trueif memory[startIndex] != 1:return memory[startIndex]# 遍历所有可能的拆分位置for i in range(startIndex, len(s)):word = s[startIndex:i + 1]  # 截取子串if word in wordSet and self.backtracking(s, wordSet, memory, i + 1):# 如果截取的子串在字典中,并且后续部分也可以被拆分成单词,返回Truereturn Truememory[startIndex] = 0# 无法进行有效拆分,返回Falsereturn Falsedef wordBreak(self, s: str, wordDict: List[str]) -> bool:wordSet = set(wordDict)  # 转换为哈希集合,提高查找效率memory = [1] * len(s)return self.backtracking(s, wordSet, memory, 0)

第二题:矩阵中的最长递增路径

Leetcode329. 矩阵中的最长递增路径:困难题 (详情点击链接见原题)

定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度

解题思路
从每一个点出发,往下深搜,看它最远能到哪

class Solution:def dfs(self, matrix, x, y, memo):if memo[x][y] != 0:  # 已经遍历过的直接返回return memo[x][y]ans = 1   # 每个节点的初始路径为 1for i, j in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:if 0 <= i < len(matrix) and 0 <= j < len(matrix[0]) and matrix[x][y] < matrix[i][j]:  # 看四个方向是否有满足条件的节点去扩散ans = max(ans, self.dfs(matrix, i, j, memo) + 1)memo[x][y] = ansreturn ansdef longestIncreasingPath(self, matrix: List[List[int]]) -> int:m, n = len(matrix), len(matrix[0])memo = [[0 for _ in range(n)] for _ in range(m)]  # memo数组用来对已经遍历过节点的最长递增路径进行记忆(防止重复计算)res = 0# 1.每个点都要作为起始点遍历一下for r in range(m):for c in range(n):if memo[r][c] == 0:  # 2.已经遍历过的就不用遍历了res = max(res, self.dfs(matrix, r, c, memo))# print(memo)   # 大家可以在纸上推算一下memo数组的结果,最终打印出来对比看是否一致return res

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

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

相关文章

Python数据挖掘项目开发实战:用深度学习方法为图像中的物体进行分类

注意&#xff1a;本文下载的资源&#xff0c;与以下文章的思路有相同点&#xff0c;也有不同点&#xff0c;最终目标只是让读者从多维度去熟练掌握本知识点。 使用Python进行数据挖掘项目开发&#xff0c;采用深度学习方法为图像中的物体进行分类&#xff0c;可以按照以下步骤进…

Spring cloud 和dubbo--一起学习吧之架构

Spring Cloud和Dubbo都是用于构建分布式系统的框架&#xff0c;但它们在定位、生态环境、调用方式、组件差异等方面有所不同。 一、定义 Spring Cloud是一个微服务架构下的一站式解决方案&#xff0c;它利用Spring Boot的开发便利性&#xff0c;巧妙地简化了分布式系统基础设…

【Qt】:对话框(二)

对话框 一.消息对话框&#xff08;QMessageBox&#xff09;1.自己构建2.使用静态函数构建 二.颜色对话框&#xff08;QDialog&#xff09;三.文件对话框&#xff08;QFileDialog&#xff09;四.字体对话框&#xff08;QFontDialog&#xff09;五.输入对话框&#xff08;QInputD…

Android Studio 常见问题解决

Unsupported Java. Your build is currently configured to use Java 17.0.9 and Gradle 6.7.1. gradle版本和 java 版本不匹配&#xff0c;导致无法编译成功, 建议降低android studio java版本配置 File -》Settings-》Build, Execution, Deployment-》Build Tools-》Gradle…

沐风老师3DMAX物品摆放插件ObjectPlacer安装和使用方法详解

3DMAX物品摆放插件ObjectPlacer安装和使用教程 3DMAX物品摆放插件ObjectPlacer&#xff0c;一键在曲面上摆放对象&#xff0c;如摆放家具物品、种植花草树木、布设电线杆交通标志等。它的功能是将对象与几何体对象&#xff08;网格、多边形、面片或NURBS&#xff09;的面法线对…

中电金信:夯实云原生时代的系统韧性建设——中电金信混沌工程金融业实践

IT系统建设在经历过单机、集中、分布式的演变历程后&#xff0c;系统运维演练、故障模拟测试的复杂度也不断提高。在复杂的分布式系统中&#xff0c;基础设施、应用平台都可能产生不可预知的故障&#xff0c;在不能确知故障根源的情况下&#xff0c;我们无法阻止故障的发生。更…

AI人工智能讲师叶梓:语言模型的推理、行动与规划:LATS框架的探索与实践

在人工智能的发展历程中&#xff0c;语言模型的推理、行动和规划能力一直是研究的重点。近期&#xff0c;一种名为LATS&#xff08;语言智能树搜索&#xff09;的通用框架引起了广泛关注&#xff0c;它成功地将大型语言模型&#xff08;LLMs&#xff09;的规划、行动和推理能力…

3D可视化技术:研发基地的科技新篇章

在科技日新月异的今天&#xff0c;我们生活在一个充满无限可能性的时代。而在这个时代中&#xff0c;3D可视化技术正以其独特的魅力&#xff0c;引领着科技领域的新一轮变革。 3D可视化技术通过三维图像的方式&#xff0c;将现实世界或虚拟世界中的物体、场景等以立体、逼真的形…

Mockito单元测试

文章目录 Mockito单元测试 为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法&#xff0c;自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(…

04—常用方法和正则表达式

一、字符串 1.length 属性返回字符串的长度(字符数)。 2.在字符串中查找字符串 indexOf() 字符串使用 indexOf() 来定位字符串中某一个指定的字符首次出现的位置 如果没找到对应的字符函数返回-1 lastIndexOf() 方法在字符串末尾开始查找字符串出现的位置。 3.replace() 方…

网络字节序

什么是网络字节序 网络字节序是网络传输的过程中所采用的字节序,那么网络传输的过程中一般都采用什么字节序呢? 答案是大端字节序。 字节序分为大端和小端,他们代表多字节数值在内存中的存储方式。下面咱们讲解一下什么是大端,什么是小端? 大端字节序:数值的最高位字…

Hive:trunc函数

一、日期 TRUNC函数为指定元素而截去的日期值。 其具体的语法格式&#xff1a;TRUNC&#xff08;date[,fmt]&#xff09; 其中&#xff1a; date 一个日期值 fmt 日期格式 -- 如果当日日期是&#xff1a;2022-11-02 select trunc(2022-11-02,MM)        --2022-11-01 …

Linux安装docker(含Centos系统和Ubuntu系统)

一、Centos系统 1. 卸载旧版本依赖 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 2. 设置仓库 安装所需的软件包。yum-utils 提供了 yum-config-manager &…

实时传输,弹性优先——物联网通讯打造数据上传新标杆

随着信息技术的飞速发展&#xff0c;物联网技术已经成为连接物理世界和数字世界的桥梁。在物联网领域&#xff0c;数据上传的速度、稳定性和灵活性是评价通讯技术优劣的重要指标。近年来&#xff0c;物联网通讯在实时传输、弹性优先方面取得了显著进展&#xff0c;为数据上传树…

设计模式:时序图

设计模式&#xff1a;时序图 设计模式&#xff1a;时序图时序图元素&#xff08;Sequence Diagram Elements&#xff09;角色&#xff08;Actor&#xff09;对象&#xff08;Object&#xff09;生命线&#xff08;Lifeline&#xff09;控制焦点&#xff08;Focus of Control&am…

Spring Boot 统一功能处理(三)

本篇主要介绍Spring Boot的统一异常处理。 目录 一、统一异常处理的使用 二、测试统一异常处理效果 三、浅析原理 ControllerAdvice简析 统一处理异常简析 一、统一异常处理的使用 在前面介绍统一数据返回时&#xff0c;我们在程序发生异常时会把整个报错信息都封装在da…

Paper 4问 迅速理清框架

读paper的时候带这个思路去读 1.What is the research problem, and what is the significance of the research? 2.What is state-of-the-art research status of the research problem? 3.Describe the methodology of the paper, and describe the advantage of the prop…

ELK日志收集和备份填坑实战 (滞后8个小时等时区问题)

ES的备份&#xff1a;ES快照备份 根据时间&#xff0c;每天零点在Linux机器crontab来调用api接口实现快照备份&#xff0c;通过快照备份&#xff0c;可以定准恢复到某一天的日志。 现象&#xff1a;&#xff08;坑&#xff1a;但是恢复某一天日志&#xff0c;发现会少8小时的日…

《云原生安全攻防》-- 云原生攻防矩阵

在本节课程中&#xff0c;我们将开始学习如何从攻击者的角度思考&#xff0c;一起探讨常见的容器和K8s攻击手法&#xff0c;包含以下两个主要内容&#xff1a; 云原生环境的攻击路径: 了解云原生环境的整体攻击流程。 云原生攻防矩阵: 云原生环境攻击路径的全景视图&#xff0…

Python数据可视化库—Bokeh与Altair指南【第161篇—数据可视化】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在数据科学和数据分析领域&#xff0c;数据可视化是一种强大的工具&#xff0c;可以帮助我们…