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

《剑指 Offer》专项突破版 - 面试题 98、99 和 100 : 和动态规划相关的矩阵路径问题(C++ 实现)

目录

前言

面试题 98 : 路径的数目

面试题 99 : 最小路径之和

面试题 100 : 三角形中最小路径之和


 


前言

矩阵路径是一类常见的可以用动态规划来解决的问题。这类问题通常输入的是一个二维的格子,一个机器人按照一定的规则从格子的某个位置走到另一个位置,要求计算路径的条数或找出最优路径

矩阵路径相关问题的状态转移方程通常有两个参数,即 f(i, j) 的两个参数 i、j 通常是机器人当前到达的坐标。需要根据路径的特点找出到达坐标 (i, j) 之前的位置,通常是坐标 (i - 1, j - 1)、(i - 1, j)、(i, j - 1) 中的一个或多个。相应地,状态转移方程就是找出 f(i, j) 与 f(i - 1, j - 1)、f(i - 1, j) 或 f(i, j - 1) 的关系

可以根据状态转移方程写出递归代码,但值得注意的是一定要将 f(i, j) 的结果用一个二维数组缓存,以避免不必要的重复计算。也可以将计算所有 f(i, j) 看成填充二维表格的过程,相应地,可以创建一个二维数组并逐一计算每个元素的值。通常,矩阵路径相关的问题的代码都可以优化空间效率,用一个一维数组就能保存所有必需的数据

接下来列举几个高频的矩阵类型的问题。


面试题 98 : 路径的数目

题目

一个机器人从 m x n 的格子的左上角出发,它每步要么向下要么向右,直到抵达格子的右下角。请计算机器人从左上角到达右下角的路径的数目。例如,如果格子的大小是 3 x 3,那么机器人从左上角到达右下角有 6 条符合条件的不同路径,如下图所示。

分析

机器人每次只能走一步,它从格子的左上角到达右下角需要走多步。机器人每走一步都有两个选择,要么向下走要么向右走。一个任务需要多个步骤才能完成,每步面临若干选择,这类问题看起来可以用回溯法解决,但由于这个题目只要求计算从左上角到达右下角的路径的数目,并没有要求列出所有的路径,因此这个问题更适合用动态规划解决。

分析确定状态转移方程

应用动态规划解决问题的关键在于找出状态转移方程。可以用函数 f(i, j) 表示从格子的左上角坐标为 (0, 0) 的位置出发到达坐标为 (i, j) 的位置的路径的数目。如果格子的大小为 m x n,那么 f(m - 1, n - 1) 就是问题的解

  1. 当 i 等于 0 时,机器人位于格子最上面一行,机器人不可能从某个位置向下走一步到达一个行号 i 等于 0 的位置。因此,f(0, j) 等于 1,即机器人只有一种方法可以到达坐标为 (0, j) 的位置,即从 (0, j - 1) 的位置向右走一步

  2. 当 j 等于 0 时,机器人位于格子最左边的一列,机器人不可能从某个位置向右走一步到达一个行号 j 为 0 的位置,因此,f(i, 0) 等于 1,即机器人只有一种方法可以到达坐标为 (i, 0) 的位置,即从 (i - 1, 0) 的位置向下走一步

  3. 当行号 i、列号 j 都大于 0 时,机器人有两种方法可以到达坐标为 (i, j) 的位置。它既可以从坐标 (i - 1, j) 的位置向下走一步,也可以从坐标 (i, j - 1) 的位置向右走一步,因此,f(i, j) 等于 f(i - 1, j) 与 f(i, j - 1) 之和

class Solution {
public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m, vector<int>(n, 1));for (int i = 1; i < m; ++i){for (int j = 1; j < n; ++j){dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}
};

上述代码用一个二维数组 dp 保存 f(i, j) 的计算结果,f(i, j) 保存在 dp[i][j] 中。

上述代码的时间复杂度和空间复杂度都是 O(mn)。

优化空间效率

接下来尝试优化代码的空间效率。在计算 f(i, j) 时只需要用到 f(i - 1, j) 和 f(i, j - 1) 的值,因此只需要保存标号分别为 i - 1 和 i 的两行就可以。如果创建一个只有两行的二维数组 dp,将 f(i, j) 保存在 dp[i % 2][j] 中,那么就将空间复杂度优化到 O(n)。

还可以进一步优化空间效率,只需要创建一个一维数组 dp 就可以。在计算 f(i, j) 时需要用到 f(i - 1, j) 和 f(i, j - 1) 的值。接下来在计算 f(i, j + 1) 时需要用到 f(i - 1, j + 1) 和 f(i, j) 的值。在计算完 f(i, j) 之后就不再需要 f(i - 1, j) 的值。在二维表格中,f(i, j) 和 f(i - 1, j) 是上下相邻的两个位置。由于在用 f(i - 1, j) 计算出 f(i, j) 之后就不再需要 f(i - 1, j),因此可以只用一个位置来保存 f(i - 1, j) 和 f(i, j) 的值。这个位置在计算 f(i, j) 之前保存的是 f(i - 1, j) 的值,计算 f(i, j) 之后保存的是 f(i, j) 的值。由于每个位置能够用来保存两个值,因此只需要一个一维数组就能保存表格中的两行

class Solution {
public:int uniquePaths(int m, int n) {vector<int> dp(n, 1);for (int i = 1; i < m; ++i){for (int j = 1; j < n; ++j){dp[j] += dp[j - 1];}}return dp[n - 1];}
};

上述代码的时间复杂度仍然是 O(mn),但空间复杂度被优化到 O(n)


面试题 99 : 最小路径之和

题目

在一个 m x n(m、n 均大于 0)的格子中,每个位置都有一个数字。一个机器人每步只能向下或向右,请计算它从格子的左上角到达右下角的路径的数字之和的最小值。例如,从下图中 3 x 3 的格子的左上角到达右下角的路径的数字之和的最小值是 8,图中数字之和最小的路径用灰色背景表示。

分析

和面试题 98 类似,机器人从格子的左上角到达右下角需要多步,每步都可能有向下或向右两个选择。由于这个题目并没有要求列出所有的路径,而是求出路径的数字之和的最小值,也就是求最优解,因此这个问题适合应用动态规划求解。

分析确定状态转移方程

应用动态规划解决问题的关键在于找出状态转移方程。用函数 f(i, j) 表示从格子的左上角坐标为 (0, 0) 的位置(用 grid[0][0] 表示)出发到达坐标为 (i, j) 的位置(用 grid[i][j] 表示)的路径的数字之和的最小值。如果格子的大小为 m x n,那么 f(m - 1, n - 1) 就是问题的解

\begin{cases} f(0, 0) = grid[0][0] \\ f(0, j) = f(0, j - 1) + grid[0][j], j > 0 \\ f(i, 0) = f(i - 1, 0) + grid[i][0], i > 0 \\ f(i, j) = min(f(i - 1, j), f(i, j - 1)) + grid[i][j], i, j > 0 \end{cases}

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<vector<int>> dp(m, vector<int>(n));dp[0][0] = grid[0][0];for (int j = 1; j < n; ++j){dp[0][j] = dp[0][j - 1] + grid[0][j];}
​for (int i = 1; i < m; ++i){dp[i][0] = dp[i - 1][0] + grid[i][0];for (int j = 1; j < n; ++j){dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[m - 1][n - 1];}
};

上述代码用二维数组 dp 保存状态转移方程的计算结果,f(i, j) 保存在 dp[i][j] 中。

上述代码的时间复杂度和空间复杂度都是 O(mn)。

优化空间效率

由于计算 f(i, j) 时只需要用到它上面一行的 f(i - 1, j),因此实际上只需要保存两行就可以。也就是说,创建一个只有两行的数组 dp,将 f(i, j) 保存到 dp[i % 2][j] 中即可。

还可以进一步优化空间效率,即只需要一个一维数组 dp。在计算 f(i, j) 时需要 f(i - 1, j) 的值。值得注意的是,f(i - 1, j) 在完成 f(i, j) 的计算之后再也用不到了,因此将 f(i - 1, j) 和 f(i, j) 保存到同一个数组 dp 的同一个位置 dp[j] 中。在计算 f(i, j) 之前,dp[j] 保存的是 f(i - 1, j) 的值,用 f(i - 1, j) 的值计算出 f(i, j) 的值之后,将 f(i, j) 的值保存到 dp[j] 中。虽然之前保存在 dp[j] 中的 f(i - 1, j) 的值被覆盖了,但这个值也不再需要,它被覆盖不会带来任何问题

class Solution {
public:int minPathSum(vector<vector<int>>& grid) {int m = grid.size(), n = grid[0].size();vector<int> dp(n);dp[0] = grid[0][0];for (int j = 1; j < n; ++j){dp[j] = dp[j - 1] + grid[0][j];}
​for (int i = 1; i < m; ++i){dp[0] += grid[i][0];for (int j = 1; j < n; ++j){dp[j] = min(dp[j], dp[j - 1]) + grid[i][j];}}return dp[n - 1];}
};

优化之后的代码的时间复杂度仍然是 O(mn),但空间复杂度变成了 O(n)


面试题 100 : 三角形中最小路径之和

题目

在一个由数字组成的三角形中,第 1 行有 1 个数字,第 2 行有 2 个数字,以此类推,第 n 行有 n 个数字。例如,下图是一个包含 4 行数字的三角形。如果每步只能前往下一行中相邻的数字,请计算从三角形顶部到底部的路径经过的数字之和的最小值。如下图所示,从三角形顶部到底部的路径数字之和的最小值为 11,对应的路径经过的数字用阴影表示。

分析

可能需要用矩阵坐标来定位三角形中的数字。上图中的相邻两行数字的位置相互交错,这样很难用矩阵坐标来表示数字的位置。可以移动三角形每行的位置使它们左端对齐,如下图所示。对齐之后就能很方便地用矩阵的行坐标和列坐标来定位每个数字。如果三角形有 n 行数字,将这些行左端对齐之后就成了一个 n x n 的矩阵和左下半部分。如果三角形中某个数字在矩阵中的行号和列号分别是 i 和 j,那么 i >= j

在左端对齐的三角形中,从一个数字出发,下一步要么前往下一行正下方的数字,要么前往右下方的数字。例如,在上图的三角形中从顶部的数字 2 出发,可以前往第 2 行位于它正下方的数字 3,也可以前往右下方的数字 4。

如果一个三角形有多行,那么从它的顶部到底部需要多步,而且每步都面临两个选择。例如,在上图的三角形中,从顶部数字 2 出发,下一步既可能前往第 2 行的第 1 个数字 3,也可能前往第 2 行的第 2 个数字 4。解决一个问题需要多个步骤,而且每个步骤都面临多个选择,这看起来可以用回溯法解决。但这个题目并没有要求列出从顶部到底部的所有路径,而是要求计算路径之和的最小值,也就是求最优解。因此,动态规划更适合解决这个问题。

分析确定状态转移方程

应用动态规划解决问题的关键在于确定状态转移方程。可以用 f(i, j) 表示从三角形的顶部出发到达行号和列号分别为 i 和 j(i >= j)的位置时路径数字之和的最小值,同时用 T[i][j] 表示三角形行号和列号分别为 i 和 j 的数字。如果三角形中包含 n 行数字,那么 f(n - 1, j) 的最小值就是整个问题的最优解

  1. f(0, 0) 等于 T[0][0]

  2. 如果 j 等于 0,也就是当前到达某行的第 1 个数字。由于路径的每步都是前往正下方或右下方的数字,而此时当前位置的左上方没有数字,那么前一步一定是来自它的正上方的数字,因此 f(i, 0) 等于 f(i - 1, 0) 与 T[i][0] 之和(i > 0)

  3. 如果 i 等于 j,也就是当前到达某行的最后一个数字,此时它的正上方没有数字,前一步只能是来自它左上方的数字,因此 f(i, j) 等于 f(i - 1, j - 1) 与 T[i][j] 之和(i > 0)

  4. 如果当前行号和列号分别为 i 和 j 的位置位于某行的中间,那么前一步既可能是来自它正上方的数字(行号和列号分别为 i - 1 和 j),也可能是来自它左上方的数字(行号和列号分别为 i - 1 和 j - 1),所以 f(i, j) 等于 f(i - 1, j) 与 f(i - 1, j - 1) 的最小值再加上 T[i][j]

class Solution {
public:int minimumTotal(vector<vector<int>>& triangle) {int n = triangle.size();vector<vector<int>> dp(n, vector<int>(n));dp[0][0] = triangle[0][0];for (int i = 1; i < n; ++i){for (int j = 0; j <= i; ++j){dp[i][j] += triangle[i][j];if (j == 0)dp[i][j] += dp[i - 1][j];else if (j == i)dp[i][j] += dp[i - 1][j - 1];elsedp[i][j] += min(dp[i - 1][j], dp[i - 1][j - 1]);}}
​int result = INT_MAX;for (int num : dp[n - 1]){result = min(result, num);}return result;}
};

上述代码创建了一个 n x n(n 为三角形的行数)的二维数组 dp,但实际上只用到了数组的左下半部分。先用一个二重循环按照状态转移方程逐一计算 f(i, j) 的值并保存到 dp[i][j] 中,然后用一个 for 循环找出二维数组 dp 最后一行的最小值作为整个问题的最优解

上述代码的时间复杂度和空间复杂度都是 O(n^2)。

优化空间效率

由于计算 f(i, j) 时只需要用到它上面一行的 f(i - 1, j) 和 f(i - 1, j - 1),因此实际上只需要保留两行就可以。也就是说,创建一个只有两行的数组 dp,将 f(i, j) 保存到 dp[i % 2][j] 中即可。

还可以考虑进一步优化空间效率,即能否只需要一个一维数组 dp。如果能够将 f(i, j) 和 f(i - 1, j) 都保存到 dp[j] 中,那么一个一维数组就可以保存所需的数据

假设在计算 f(i, j) 之前 dp[j] 中保存的是 f(i - 1, j) 的值。在计算 f(i, j) 时需要 f(i - 1, j - 1) 和 f(i - 1, j)。在计算完 f(i, j) 之后能否用 f(i, j) 的值覆盖保存在 dp[j] 中的 f(i - 1, j) 取决于是否还需要 f(i - 1, j) 的值

  1. 如果每行按照从左到右的顺序,那么在计算完 f(i, j) 之后将计算 f(i, j + 1),而计算 f(i, j + 1) 可能需要 f(i - 1, j) 和 f(i - 1, j + 1) 的值,也就是 f(i - 1, j) 的值在计算 f(i, j + 1) 时可能会被用到,因此在计算完 f(i, j) 之后不能将 f(i - 1, j) 的值丢掉

  2. 但计算 f(i, j) 时并不依赖同一行左侧的 f(i, j - 1),因此并不一定要按照从左到右的顺序计算每行,按照从右到左的顺序计算也可以。如果按照从右到左的顺序,则先计算 f(i, j),需要用到 f(i - 1, j - 1) 和 f(i - 1, j)。接下来计算 f(i, j - 1),需要用到 f(i - 1, j - 2) 和 f(i - 1, j - 1)。计算 f(i - 1, j - 1) 并不需要用到 f(i - 1, j)。因此,按照从右到左的顺序在计算完 f(i, j) 之后,将 f(i, j) 的值保存到 dp[j] 中并替换 f(i - 1, j) 的值,并且不会带来任何问题,因此 f(i - 1, j) 的值以后就不再需要

class Solution {
public:int minimumTotal(vector<vector<int>>& triangle) {int n = triangle.size();vector<int> dp(n);dp[0] = triangle[0][0];
​for (int i = 1; i < n; ++i){for (int j = i; j >= 0; --j){if (j == i)dp[j] = dp[j - 1] + triangle[i][j];else if (j == 0)dp[j] += triangle[i][j];elsedp[j] = min(dp[j - 1], dp[j]) + triangle[i][j];}}
​int result = INT_MAX;for (int num : dp){result = min(result, num);}return result;}
};

上述代码的时间复杂度仍然是 O(n^2),但空间复杂度变成了 O(n)

相关文章:

《剑指 Offer》专项突破版 - 面试题 98、99 和 100 : 和动态规划相关的矩阵路径问题(C++ 实现)

目录 前言 面试题 98 : 路径的数目 面试题 99 : 最小路径之和 面试题 100 : 三角形中最小路径之和 前言 矩阵路径是一类常见的可以用动态规划来解决的问题。这类问题通常输入的是一个二维的格子&#xff0c;一个机器人按照一定的规则从格子的某个位置走到另一个位置&#…...

KY145 EXCEL排序(用Java实现)

描述 Excel可以对一组纪录按任意指定列排序。现请你编写程序实现类似功能。 对每个测试用例&#xff0c;首先输出1行“Case i:”&#xff0c;其中 i 是测试用例的编号&#xff08;从1开始&#xff09;。随后在 N 行中输出按要求排序后的结果&#xff0c;即&#xff1a;当 C…...

属性选择器

1.[title]{background:yellow;}&#xff1a;所有带title标签设置成黄色 2.div[class]{background:yellow;}&#xff1a;所有div中带class标签设置成黄色 3.div[classbox1]{border:1px solid blue; }&#xff1a;div中包含class并且classbox1的设置成蓝边框 4. class…...

软考 - 系统架构设计师 - 关系模型的完整性规则

前言 关系模型的完整性规则是一组用于确保关系数据库中数据的完整性和一致性的规则。这些规则定义了在关系数据库中如何存储、更新和查询数据&#xff0c;以保证数据的准确性和一致性。 详情 关系模型的完整性规则主要包括以下三类&#xff1a; 实体完整性规则 这是确保每个…...

写了几个难一点的sql

写了几个难一点的sql SELECT bn.id AS book_node_id, t.version_id, bn.textbook_id, s.id AS subject_id, s.stage_id, COUNT( CASE WHEN d.document_type_id 1 AND d.scope IS NULL AND p.document_id IS NOT NULL THEN 1 END ) AS type_1_count, COUNT( CASEWHEN d.docume…...

【JDK常用的API】包装类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …...

Android Q(10)黑暗模式适配的实现

一、引言 随着 AndroidQ&#xff08;10&#xff09;的发布&#xff0c;黑暗模式成为了系统级别的特性。为了满足用户在不同环境下的使用需求&#xff0c;应用程序需要及时进行黑暗模式的适配。本文将详细介绍如何在 AndroidQ&#xff08;10&#xff09;上实现黑暗模式的适配&a…...

【git】git使用手册

目录 一 初始化 1.1 账号配置 1.2 ssh生成 1.2.1 配置ssh 1.2.2 测试SSH 1.3 初始化本地仓库并关联远程仓库 二 使用 2.1 上传 2.2 拉取 三 问题 3.1 关联失败 一 初始化 git的安装很简单,下载后大部分进行下一步完成即可----->地址: git工具下载 1.1 账号配置…...

unity中判断方向 用 KeyVertical ,KeyHorizontal 判断ui物体的 方向

float KeyVertical Input.GetAxis("Vertical"); float KeyHorizontal Input.GetAxis("Horizontal"); // 假设 UI 物体在竖直方向上为 Y 轴&#xff0c;水平方向上为 X 轴 Vector2 direction new Vector2(KeyHorizontal, KeyVertical); if (direction…...

前端a4纸尺寸转像素尺寸

前端必备工具推荐网站(免费图床、API和ChatAI等实用工具): http://luckycola.com.cn/ 一、a4纸张有多大 A4纸的尺寸是210mm297mm,也就是21.0cm29.7cm, A4纸尺寸转屏幕像素尺寸和屏幕分辨率有关,首先1英寸2.54cm, 如果屏幕DPI分辨率为72像素/英寸&#xff0c;换算一下&#xff…...

Android 中 调试和减少内存错误

Android 中 调试和减少内存错误 ASan 概述 官网连接&#xff1a; https://developer.android.com/ndk/guides/asan?hlzh-cn ASan API 27开始HWASan&#xff08;替换AScan&#xff09; 从 NDK r21 和 Android 10&#xff08;API 级别 29&#xff09;开始适用于 64 位 Arm 设…...

证券市场概述

证券市场 证券市场参与者证券发行市场&#xff08;一级市场&#xff09;证券发行方式&#xff08;按发行对象&#xff09;证券发行方式&#xff08;按有无中介&#xff09;证券交易市场&#xff08;二级市场&#xff09;证券交易所场外交易市场&#xff08;店头市场、柜台市场&…...

什么是数据结构

一、什么是数据结构 1.数据结构研究计算机数据间的关系 2.包括数据的逻辑结构和储存结构及其操作 数据的逻辑结构&#xff1a;表示数据运算之间的抽象关系 按每个元素可能具有的直接前趋数和后继数将逻辑结构分为“线性结构”和“非线性结构”两大类 数据的储存结构&#…...

基于springboot+vue实现的学校田径运动会管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…...

HarmonyOS 应用开发之FA模型绑定Stage模型ServiceExtensionAbility

本文介绍FA模型的三种应用组件如何绑定Stage模型的ServiceExtensionAbility组件。 PageAbility关联访问ServiceExtensionAbility PageAbility关联访问ServiceExtensionAbility和PageAbility关联访问ServiceAbility的方式完全相同。 import featureAbility from ohos.ability…...

Java 中的单例模式

引言&#xff1a; 在 Java 编程中&#xff0c;单例模式是一种常见的设计模式&#xff0c;它保证一个类只能创建一个实例&#xff0c;并提供一个全局访问点。单例模式在很多场景下都非常有用&#xff0c;比如线程池、日志系统、数据库连接池等。本文将详细介绍 Java 中单例模式的…...

鸿蒙OS开发实例:【ArkTS类库多线程I/O密集型任务开发】

使用异步并发可以解决单次I/O任务阻塞的问题&#xff0c;但是如果遇到I/O密集型任务&#xff0c;同样会阻塞线程中其它任务的执行&#xff0c;这时需要使用多线程并发能力来进行解决。 I/O密集型任务的性能重点通常不在于CPU的处理能力&#xff0c;而在于I/O操作的速度和效率。…...

OpenStack部署

目录 一、安装环境 1.无网络使用该命令 2.修改主机名 3.配置hosts解析 4.配置本机免密 5.关闭防火墙和SElinux策略 6.关闭NewworkManager 7.修改yum源 7.1下载阿里源 7.2清空并加载缓存yum源 8.安装基本工具 9.系统升级 10.安装OPenStack的yum仓库 11.修改OPenSt…...

Java中的多线程和线程安全问题

线程 线程是操作系统进行调度的最小单位。一个进程至少包含一个主线程&#xff0c;而一个线程可以启动多个子线程。线程之间共享进程的资源&#xff0c;但也有自己的局部变量。多线程程序和普通程序的区别&#xff1a;每个线程都是一个独立的执行流&#xff1b;多个线程之间是…...

java Web会议信息管理系统 用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 jsp 会议信息管理系统是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&am…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...