杨氏矩阵与杨表:从理论到实战的算法解析

杨氏矩阵与最长上升子序列:从理论到实战的深度解析 本文深度解析了杨氏矩阵(杨表)与最长上升子序列(LIS)的理论联系及实战应用。通过直观的杨图引入,重点阐述了RSK算法与Hook公式的核心原理,并展示了如何利用杨表将复杂的排列计数问题转化为对有限整数划分的枚举,从而高效求解LIS长度期望值等组合数学难题。 阅读详情

1. 杨氏矩阵与杨表:不只是数学的艺术品

我第一次听说杨氏矩阵和杨表,是在准备一场算法竞赛的时候。当时被一道关于最长上升子序列期望值的题目卡住了,常规的动态规划方法在数据规模面前完全失效。直到一位前辈指点说:“试试用杨表的知识,用Hook公式去枚举所有形状。” 我当时的反应和很多刚接触的朋友一样:这是什么听起来高大上的东西?跟算法有什么关系?但当我真正静下心来研究,才发现这简直是解决一类组合计数问题的“核武器”。它不像普通的动态规划那样直接,却能在看似无解的问题上,开辟出一条优雅的路径。

简单来说,你可以把杨氏矩阵(也叫杨图)想象成一种用方格堆叠起来的“图形化整数拆分”。比如,数字5可以拆成3+1+1,或者2+2+1。每一种拆分方式,都可以用一个左对齐的方格图来表示,其中每一行的方格数对应拆分中的一个加数。这种图就是杨图。而杨表,则是给这个杨图的每个格子填上数字,并且要满足一定的单调性规则。最常见的是标准杨表,要求填入1到n的所有数字,并且每行从左到右严格递增,每列从上到下严格递增。这就像是在一个不规则的棋盘上,按照严格递增的规则摆放一套编号的棋子。

那么,这个东西为什么对算法选手,尤其是处理排列、子序列问题的我们如此重要呢?核心秘密在于一个惊人的对应关系:一个1到n的排列,唯一地对应着一对形状相同的标准杨表。更妙的是,这对杨表中的第一个表(插入表P)的第一行长度,恰好就等于原排列的最长上升子序列(LIS)的长度!这个性质直接把一个动态的序列问题,转化为了一个静态的、可以枚举的图形计数问题。对于求解LIS长度的分布、期望,或者一些相关的组合数量,这个视角的转换往往是突破的关键。在接下来的内容里,我会带你从最直观的理解开始,一步步拆解杨表的构造、核心算法和那些威力巨大的公式,并用实战题目让你感受它如何化繁为简。

2. 深入核心:杨表的构造与RSK算法

理解了杨表是什么之后,最关键的问题来了:怎么从一个具体的排列,得到它对应的那个杨表呢?这个过程依赖于一个精巧的算法——Robinson-Schensted-Knuth算法,通常简称为RSK算法。这个算法是连接排列与杨表的桥梁,也是整个理论得以应用的基础。

2.1 插入操作:像整理扑克牌一样构建杨表

RSK算法的核心是“插入”操作。我更喜欢把它比喻成整理一手杂乱无章的扑克牌。假设我们有一个已经部分构建好的杨表(可能一开始是空的),现在要把一个新数字x“插入”到这个杨表中,规则如下:

  1. 从第一行开始:在当前行(最初是第一行)中,寻找第一个(即最小的)大于x的数字。你可以把每一行想象成一条已经排好序的队列。
  2. 找到则“踢走”并下沉:如果找到了这个数字y,我们就把y“踢”出当前位置,用x来占据y原来的位置。而被踢走的y,则需要带着“委屈”去下一行,尝试在那里找到自己的新位置(即重复步骤1,但以y作为新的待插入数字)。
  3. 找不到则安家:如果在当前行找不到比x大的数字(说明x比这一行所有的数都大),那么恭喜x,它可以直接站到这一行的末尾,插入过程结束。

这个插入过程一定会终止,并且终止的位置一定位于杨表的“边角”。边角指的是一个格子,它的右边和下边都没有格子了,就像一块不规则拼图最外缘的凸起。这个性质很重要。

让我用一个具体的例子来演示。假设我们已经有一个杨表,现在要插入数字6。

已有杨表(部分):
行1: 1 3 5
行2: 2 4
行3: 7

插入6的过程:

  • 第一行:寻找第一个大于6的数。1,3,5都小于6,找不到。所以6应该放在第一行末尾吗?不,我们继续看,第一行末尾之后?不对,规则是找不到大于它的数时才放末尾。这里5<6,后面没数了,所以第一行找不到大于6的数。因此,6放在第一行末尾?等等,这里有个关键点,第一行有5,小于6,但我们要找的是“第一个大于x的数”。5小于6,所以不是。检查7?7在第三行。所以第一行里所有数(1,3,5)都小于6,因此在第一行找不到大于6的数。所以,根据规则3,6应该放在第一行末尾。 但让我们更严谨地走一遍算法:从第一行开始,找第一个大于6的数。遍历1,不大于;3,不大于;5,不大于。结束,没找到。因此,将6放在第一行末尾。插入结束。新的第一行变成 1 3 5 6。注意,此时(1,4)(第1行第4列)是一个边角吗?它的右边没有格子,下边(第二行只有2列)也没有格子,所以是边角。符合算法描述。

这个例子展示了最直接的情况。再看一个“踢走”的例子:向同一个表(插入6之前的原始表)插入数字4。

  • 第一行:找第一个大于4的数。是5。于是,4把5踢走,4坐在5的位置上(第一行变成 1 3 4),被踢走的5要去第二行找位置。
  • 第二行(带着数字5):找第一个大于5的数。第二行是 2 4,2和4都小于5,找不到大于5的数。所以5放在第二行末尾(第二行变成 2 4 5)。插入结束。新位置(2,3)是边角。

通过这样逐个插入排列中的数字,我们就能构建出与排列对应的那个杨表P。这个过程是确定性的,一个排列只对应一个杨表P。

2.2 记录表Q与双射:完整的对应关系

只有插入表P还不够。RSK算法的精妙之处在于,它在构建P的同时,还会同步构建另一个形状完全相同的杨表,称为记录表Q。记录表Q记录的是“时间戳”或“插入顺序”。

规则很简单:每当一个数字在插入过程中,最终被放置在一个新的边角位置时(即插入操作终止时),我们就在记录表Q的相同位置,填入当前数字在原排列中的下标(序号)。

继续上面的例子,假设我们按顺序插入排列 [3, 1, 4, 2] 来构建标准杨表。

  1. 插入3:插入空表,3放在(1,1)。这是新边角,所以在Q的(1,1)位置记录序号1。 P: [[3]], Q: [[1]]
  2. 插入1:从第一行找大于1的数,找到3。1踢走3,1坐(1,1)。被踢走的3去第二行(新建),放在(2,1)。插入终止于(2,1),是新边角。在P中,1在(1,1),3在(2,1)。在Q中,当插入终止于(2,1)时,记录当前序号2。注意,Q的(1,1)已经被1占据了吗?不,Q记录的是终止位置。这里有两个终止位置?让我们仔细想:这次插入,数字1最终占据了(1,1),但(1,1)在插入前是空位吗?不,插入前(1,1)是3。根据算法,1把3从(1,1)踢走,自己坐进去。那么(1,1)是这次插入的终止位置吗?不是,因为1踢走3后,3还要继续插入。这次插入真正的终止,是3被放到(2,1)的时候。所以,只在最终放置新数字(导致插入过程结束)的那个边角位置,记录序号。因此,只在Q的(2,1)记录序号2。 此时 P: [[1], [3]], Q: [[?], [2]]。Q的(1,1)是什么?它应该记录第一次插入3时终止的位置(1,1)的序号1。所以 Q: [[1], [2]]。
  3. 插入4:从第一行找大于4的数,第一行只有1,小于4,找不到。所以4放在第一行末尾(1,2)。是新边角,在Q的(1,2)记录序号3。 P: [[1, 4], [3]], Q: [[1, 3], [2]]
  4. 插入2:从第一行找大于2的数,找到4。2踢走4,坐(1,2)。被踢走的4去第二行找位置。第二行是3,找大于4的数,找不到,所以4放在第二行末尾(2,2)。是新边角,在Q的(2,2)记录序号4。 最终 P: [[1, 2], [3, 4]], Q: [[1, 3], [2, 4]]

这样,我们就得到了一对形状相同的标准杨表(P, Q)。Robinson-Schensted对应指出,1到n的每一个排列,与所有形状相同的标准杨表对(P, Q)之间存在一一对应(双射)。这个定理是组合数学中的一个经典结果,它意味着我们可以通过枚举杨表对来研究排列的性质,反之亦然。

3. 威力强大的工具:Hook公式与计数

当我们通过RSK算法把排列问题转化为杨表形状的问题后,下一个挑战就是:对于一个给定的杨图形状(即一个整数拆分λ),有多少种不同的方式能填出一个标准杨表?换句话说,这个形状对应了多少个排列?Hook公式(勾长公式)就是回答这个问题的神兵利器。

3.1 什么是勾长?

勾长公式的名字很形象。杨图中每一个方格,都有一个“钩子”。这个钩子包括:

  • 该方格本身。
  • 该方格右边的所有方格(同一行)。
  • 该方格下边的所有方格(同一列)。

钩子所覆盖的方格总数,就是这个方格的勾长。例如,在一个形状为(3,2,1)的杨图中(即第一行3格,第二行2格,第三行1格),左上角(1,1)的方格,它的右边有2格,下边有2格,加上自己,勾长就是1+2+2=5。

计算勾长是机械的。你需要做的是,对于给定形状的杨图,计算出每一个格子的勾长。

3.2 Hook公式的内容与应用

Hook公式告诉我们:对于一个有n个方格的杨图(对应整数n的一个拆分λ),其标准杨表的填法数目为:

f^λ = n! / (所有方格勾长的乘积)

是的,公式就这么简洁!n! 是n个数字的所有排列总数。分母是所有格子勾长的乘积。这个公式将复杂的组合计数,简化成了简单的乘除法。

为什么这个公式如此有用?在算法竞赛中,我们经常需要计算满足某种条件的排列个数。如果这种条件能对应到杨表的形状上(比如LIS长度等于杨表第一行长度),那么问题就变成了:

  1. 枚举所有可能的杨图形状(即n的所有整数拆分)。
  2. 对每个形状λ,用Hook公式计算 f^λ,即能填出该形状标准杨表的排列数(也就是产生该形状P表的排列数)。
  3. 由于双射,每一对(P,Q)对应一个排列,而形状λ的标准杨表P的个数是 f^λ,标准杨表Q的个数也是 f^λ,所以对应这个形状的排列数就是 (f^λ)^2吗?这里需要小心。RSK双射是一个排列对应一对(P,Q)。对于一个固定的形状λ,有多少对(P,Q)呢?有 f^λ 个可能的P,和 f^λ 个可能的Q,所以总共有 f^λ * f^λ = (f^λ)^2 对(P,Q)。根据双射,这正好就对应了 (f^λ)^2 个排列。但是,所有形状的排列数总和应该等于n!。实际上,有一个著名的等式:Σ_λ (f^λ)^2 = n!,其中求和遍历n的所有整数拆分λ。这从侧面验证了双射的正确性。

在实际解题时,我们通常关心的是具有特定性质的排列数,例如LIS长度 = k的排列有多少个。根据RSK对应,这等价于第一行长度恰好为k的标准杨表P有多少个。而第一行长度为k的杨图形状,就是那些拆分λ满足 λ₁ = k 的形状。对于每个这样的形状λ,能填出的标准杨表P的个数就是 f^λ。那么,对应的排列数是不是 f^λ * f^λ 呢?不完全是。因为一个排列对应一对(P,Q)。当我们说“LIS长度=k的排列数”时,我们是在数排列。对于某个固定形状λ(第一行长度=k),能产生这种P的排列数,正是所有Q与这个P配对的数目,也就是 f^λ(因为Q可以是任何同形状的标准杨表)。所以,对于这个特定的λ,对应的排列数就是 f^λ(个P表)乘以 f^λ(个Q表)再除以……等等,这里逻辑有点绕。让我们重新梳理:

  • 目标:计算LIS长度 = k的排列数。
  • 根据RSK:排列π -> (P, Q),且 LIS(π) = P的第一行长度。
  • 所以,LIS(π)=k 当且仅当 P的第一行长度 = k。
  • 现在,固定一个形状λ,使得λ₁ = k。有多少个排列π,其对应的P表形状是λ?根据双射,这样的排列π与所有形状为λ的(P, Q)对一一对应。
  • 形状为λ的P表有多少个?Hook公式给出 f^λ。
  • 形状为λ的Q表有多少个?同样是 f^λ。
  • 因此,形状为λ的(P, Q)对一共有 f^λ * f^λ 个。
  • 这 f^λ * f^λ 个对,就对应了 f^λ * f^λ 个排列,这些排列的P表形状都是λ,因而LIS长度都是k。

所以,对于所有满足λ₁=k的形状λ,把它们对应的 (f^λ)^2 加起来,就得到了LIS长度 = k的总排列数。

有了这个框架,求LIS长度的期望值就变成了一个可计算的问题:期望 = Σ (k * LIS长度为k的排列数) / n!。而分子部分,就是 Σ [k * Σ_{λ: λ₁=k} (f^λ)^2]。Hook公式让计算 f^λ 成为可能,从而让整个问题从动态规划的死胡同里跳了出来,变成了一个优雅的组合枚举问题。

4. 实战解析:BJWC2018最长上升子序列期望

理论讲得再多,不如真刀真枪解决一个问题。我们来看一道经典题目:[BJWC2018]最长上升子序列。题意很简单:求长度为n(n<=28)的随机排列,其最长上升子序列(LIS)长度的期望值。答案对998244353取模。

如果直接用动态规划求每个排列的LIS然后平均,复杂度是O(n! * n log n),完全不可行。即使使用状压DP记录状态,在n=28时状态数也过于庞大。这时候,杨表和Hook公式的组合拳就派上用场了。

4.1 解题思路拆解

我们的核心思路,就是利用前面阐述的理论:

  1. 排列与杨表双射:每个排列对应一对形状相同的标准杨表(P, Q),且LIS长度等于P表第一行长度。
  2. 枚举形状而非排列:我们不枚举排列,而是枚举n的所有整数拆分(即杨图形状)。n=28时,拆分数p(28)大概在2000量级,这是完全可以暴力枚举的。
  3. Hook公式计数:对于每个枚举出的形状λ(一个整数拆分列表,如[λ₁, λ₂, ...]),我们用Hook公式计算出 f^λ,即这个形状的标准杨表填法数。
  4. 计算贡献:对于形状λ,其第一行长度 len = λ₁。所有P表形状为λ的排列有多少个?根据双射,是 (f^λ)^2 个。每一个这样的排列,其LIS长度就是 len。所以,形状λ对所有排列LIS长度总和的贡献是 len * (f^λ)^2。
  5. 期望计算:遍历所有形状λ,将贡献累加,得到所有排列的LIS长度总和 total_sum。排列总数为 n!。期望值 E = total_sum / n!。

因此,问题转化为:如何高效枚举所有整数拆分,并对每个拆分快速计算Hook公式的值 f^λ。

4.2 代码实现与关键细节

下面结合代码片段,讲解实现中的关键点。代码使用DFS来枚举整数拆分。

#include<bits/stdc++.h>
using namespace std;
const int N=30, mod=998244353;
int n, inv[N], a[N], ans;
// a数组存储当前的整数拆分,a[1]...a[y-1]是已确定的部分,a[i]表示第i行的格子数
// x 表示剩余待分配的数字总和
// y 表示当前准备决定第几行的长度
void dfs(int x, int y) {
    if(!x) { // 剩余为0,一个完整的拆分产生了
        // 计算当前拆分形状λ对应的 f^λ,根据Hook公式: f^λ = n! / Π(每个格子的勾长)
        // 我们先计算分母,即所有格子勾长的乘积
        int res = 1;
        // 先乘上 n!
        for(int i=1; i<=n; ++i) res = 1LL * res * i % mod;

        // 遍历每一行 i (从1到y-1)
        for(int i=1; i<y; ++i) {
            // 遍历该行每一列 j (从1到a[i])
            for(int j=1; j<=a[i]; ++j) {
                int hook = a[i] - j; // 同一行右边的格子数
                // 加上同一列下面的格子数
                for(int k=i+1; k<y; ++k) { // 遍历下面的行
                    if(a[k] >= j) hook++; // 如果下面第k行的长度>=j,说明第j列有格子
                }
                hook++; // 加上自己
                // Hook公式分母是连乘,这里转化为乘逆元
                res = 1LL * res * inv[hook] % mod;
            }
        }
        // 此时res = f^λ
        // 该形状对总和的贡献是 λ₁ * (f^λ)^2
        int contribution = 1LL * res * res % mod * a[1] % mod; // a[1]就是λ₁
        ans = (ans + contribution) % mod;
        return;
    }
    // 枚举下一行的长度i,长度不能超过剩余数x,也不能超过上一行的长度(保证行长度非递增)
    for(int i=1; i<=x; ++i) {
        if(y != 1 && i > a[y-1]) continue; // 保证拆分是递减的,避免重复枚举
        a[y] = i;
        dfs(x-i, y+1);
    }
}
int main() {
    scanf("%d", &n);
    // 预处理1到n的模逆元,用于Hook公式中的除法
    inv[1] = 1;
    for(int i=2; i<=n; ++i) {
        inv[i] = 1LL * (mod - mod/i) * inv[mod%i] % mod;
    }
    ans = 0;
    dfs(n, 1); // 初始:总和为n,从第1行开始
    // 此时ans是所有形状的贡献总和 Σ [λ₁ * (f^λ)^2]
    // 期望 E = ans / n!
    for(int i=1; i<=n; ++i) {
        ans = 1LL * ans * inv[i] % mod; // 连续乘上 1/i,即除以 n!
    }
    printf("%d\n", ans);
    return 0;
}

几个需要特别注意的细节:

  1. 枚举去重:整数拆分 5=3+2 和 5=2+3 在杨图中是同一个形状(第一行3格,第二行2格)。我们的DFS通过限制 i <= a[y-1](即下一行长度不超过上一行)来保证生成的是非递增序列,从而自动去重。
  2. 勾长计算:代码中双重循环计算每个格子 (i, j) 的勾长。a[i] - j 是同行右边的格子数。内层循环 for(int k=i+1; k<y; ++k) 是计算同列下面的格子数,条件是下面行的长度 a[k] 要大于等于当前列号 j。
  3. 模运算处理:Hook公式涉及除法,在模质数 mod=998244353 下,我们通过预处理所有数字的逆元 inv[i],将除法转换为乘法。
  4. 贡献计算:最终答案 ans 在DFS结束后存储的是 Σ [λ₁ * (f^λ)^2]。最后需要除以 n! 得到期望。因为 n! 是 1*2*...*n 的乘积,所以我们连续乘上 inv[1], inv[2], ..., inv[n] 来实现除法。

4.3 复杂度分析与优化点

这个算法的核心复杂度取决于整数拆分的数量 p(n)。对于 n=28,p(28) 大约是 2000 量级。对于每个拆分,我们需要计算其所有格子的勾长,最坏情况下格子数是 n,计算每个格子勾长需要遍历其下方的行,最坏是 O(n)。所以总复杂度大约是 O(p(n) * n^2),在 n=28 时完全可行。

如果 n 更大(比如达到50或100),拆分数会急剧增长(p(50)~20万,p(100)~1.9亿),暴力枚举所有拆分就不现实了。这时候往往需要结合动态规划或其他计数技巧,或者利用杨表性质的数学推导来直接求解,这通常就属于更深入的组合数学领域了。但对于算法竞赛中的此类问题,n 的范围通常设计得正好让这种优雅的暴力枚举方法能够通过,考察的正是选手对杨表这一工具的理解和运用能力。

通过这道题,我们可以深刻体会到,将序列的LIS问题转化为杨图的形状枚举问题,是如何将一个 O(n!) 级别的恐怖问题,降维到一个 p(n) 级别的可解问题的。这种思维上的跃迁,正是学习高级算法和组合数学的乐趣所在。

5个4000比特大状态置换算法的设计与分析 下面是 5 个概念性、实验性的 4000 位可逆置换设计。它们都保证是双射,但未经过密码分析,不可直接用于生产系统。风格分别覆盖:三维 SPN、Feistel、可逆元胞自动机、ARX、宽轨迹/Keccak 式结构。 这 5 个设计分别代表了 SPN、Feistel、元胞自动机、ARX、宽轨迹 Keccak 五种不同风格,覆盖了主流大状态置换的构造思路。再次强调:它们只是实验性概念,若要用于实际协议,必须经过严格安全性分析。 阅读详情

相关推荐

匈牙利算法解决指派问题清晰流程

匈牙利算法解决指派问题清晰流程 百度词条上,指派问题(Assignment problem)是这么定义的:在满足特定指派要求条件下,使指派方案总体效果最佳。如:有若干项工作需要分配给若干人(或部门)来完成;有若干项合同需要选择若干个投标者来承包:有若干班级需要安排在若干教室里上课等。   一、做减法(归约): 行归约:每行元素减去该行最小元素。 列归约:每行元素减去该行最小元素。

siss0siss的博客 6万+

从杨氏矩阵到算法竞赛:用Python实现RSK双射的完整指南(附BJWC2018题解)

本文详细介绍了如何利用Python实现RSK双射算法,从杨氏矩阵的基础概念到算法竞赛应用。通过杨表可视化、RSK算法实现及Hook公式计算,帮助开发者深入理解组合数学与算法设计的结合。特别针对BJWC2018竞赛题,提供了完整的Python解决方案,适合算法爱好者和竞赛选手参考。

weixin_29083649的博客 199

SpringAi 通过大模型来实现调用自己的Api

摘要 本文介绍了如何利用Spring AI的Tools机制扩展大模型能力,实现业务系统集成。通过@Tool和@ToolParam注解定义工具方法,将订单查询和关闭功能暴露给大模型调用。关键实现包括:1)使用详细描述标注工具方法和参数;2)在ChatClient中注册工具服务;3)集成对话记忆保持上下文。该方法使AI具备操作业务系统的能力,形成"认知-决策-执行"闭环,大幅提升了模型在实际业务场景中的应用价值。

又要搬砖了 836

杨氏矩阵||钩子公式

个人理解: 求解勾长时,行朝格子数减少的方向计算。 给定一个杨表πλ ,一共有n个方格。那么把1到n这n个数字填到这个杨表中,使得每行从左到右都是递增的,每列从下到上也是递增的。用 dimπλ 表示这样的方法个数, 给定一个杨图,各方格的位置由两个座标决定,分别是行数与列数,列的顺序是由左往右数,行的顺序则是按照所包含的方格数由多的往少的方向数, 勾长: 对于杨表中的一个方格v,其勾长 hook(...

weixin_44879687的博客 864

HomeAssistant+HACS实战:5分钟搞定米家设备接入(附HomeKit配置技巧)

本文详细介绍了如何通过HomeAssistant和HACS插件商店快速接入米家设备,并分享HomeKit配置技巧。从HACS安装到米家设备接入,再到HomeKit设备集成,提供一站式智能家居解决方案,帮助用户实现设备统一管理和自动化场景设置。

weixin_29192141的博客 1050

ABAQUS应用15——Abaqus软件中边界条件与力学中自由度的关系

核心关系:Abaqus通过约束自由度实现边界条件,自由度类型由单元决定。正确设置步骤:确定模型类型(实体/梁/壳)。识别节点的自由度(平动或转动)。根据实际约束施加对应的自由度限制。验证:通过检查变形模式、反力分布等确认边界条件合理性。正确理解自由度与边界条件的关系,是确保有限元模型准确模拟实际物理行为的关键。

George的博客 1545

杨氏矩阵 Young Tableau

杨氏矩阵 Young Tableau 杨氏矩阵 Young Tableau 前几天算法课上老师提到了一个数据结构--Young Tableau,只是简单的提了一下,没有仔细的讲解,于是自己在网上搜集了一些资料,并且加以研究,感觉杨氏矩阵(Young Tableau)是一个很奇妙的数据结构,他类似于堆的结构,又类似于BST的结构,对于查找某些元素,它优于堆;对于插入、删除它比BS

远方的专栏 752

【异常】安装hermes-agent时Git克隆大仓库报错:error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CAN

摘要:本文分析了Ubuntu服务器执行Git递归克隆时出现的网络传输中断错误(HTTP/2流异常关闭、数据截断)。主要原因是网络限制、协议兼容问题和缓冲区不足。提供了四种解决方案:1)扩大Git HTTP缓冲区;2)切换为HTTP/1.1协议;3)采用浅克隆+分步拉取子模块;4)网络优化措施。重点推荐浅克隆分步拉取作为最有效方案,所有方法无需重启即可生效,可快速解决大仓库递归克隆失败问题。

奶爸的编程之路,也就一周冷个三天 670

行列有序的二维数组查找

描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 输入描述: array: 待查找的二维数组 target:查找的数字 输出描述: 查找到返回true,查找不到返回false 解析 分冶法 这种行和列分别递增的矩阵,有一个专有名词叫做杨...

492

【第1章>第5节】SOM自组织映射网络的理论学习与MATLAB仿真

自组织映射网络(Self-Organizing Map,SOM)是一种无监督学习的人工神经网络,由芬兰学者Teuvo Kohonen于1981年提出,也被称为Kohonen网络。它的主要功能是将高维输入数据映射到低维(通常是二维)的离散网格上,同时保持输入数据的拓扑结构,即相邻的输入数据在映射后的网格上也相邻。

FPGA/MATLAB学习教程/源码/项目合作开发 402

嵌入式工程师必学(118):MCU的硬件定时器和中断

大多数微处理器都有一个或多个可编程硬件定时器,这些定时器包括对中断的支持。可以有不同类型的计时器,用于不同的应用程序。例如,LPC1768 具有四个 32 位通用定时器、一个看门狗定时器、一个重复中断定时器、一个系统滴答定时器、一个正交编码器接口、6 个 PWM 输出和一个支持中断的实时时钟。硬件定时器用于计时和计数作,允许处理器在 timer 进程运行时继续执行其他进程。硬件定时器是一种使用 clock 信号来增加 register 的电路。

码农17年的博客 211

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 228

【华为OD机试真题】459、小扇和小船的数字游戏、数字游戏 | 机试真题+思路参考+代码解析(CD卷)(C++、Java、Py)

### 🎃题目描述 >小扇和小船今天又玩起来了数字游戏,小船给小扇一个正整数 n(1  现在求 m 的最小值

KJ.JK 1718

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 315

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 592

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 21

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

C语言程序设计题|有序数组插入数字冒泡排序

题目要求将一个数插入有序数组末尾,并用冒泡排序实现整体升序。代码先将输入数存入数组最后位置,再通过双重循环进行冒泡排序,每轮将较大元素向后移动,最终输出11个升序元素。该方法虽时间复杂度为O(n²),但符合题目要求,逻辑清晰,适合初学者理解排序原理。

2301_81429079的博客 750

【算法拾光】模拟|外观数列 + 数青蛙

本文总结两道模拟题解法:外观数列通过迭代统计连续数字个数生成下一项,关键在于处理末尾字符;数青蛙则模拟青蛙叫声“croak”状态转移,维护各阶段青蛙数量,记录最大并发数并确保全部完成。共性在于严格遵循流程、细致处理边界与非法情况,锻炼字符串遍历与状态管理能力。

wuqingyigexiaoba的博客 371

408 算法 04|主元素与三元组最小距离:两种“扫描时做决定“的思路

2013(41) 的主元素用摩尔投票一遍选出候选,但真正的考点是"选完必须验票";2020(41) 的三元组最小距离,三指针每次只挪最小的那个,靠的是 D=2×(max−min) 这个恒等式。两套完整 C 代码加真实输出,附官方评分档位表。

m0_56226131的博客 412

牛客周赛165C题(前后缀性质,递推,排序,枚举)

题目大意:给定长度为 `n` 的数组,选择 `k ∈ [1,n]`,将前 `k` 个元素整体翻转,后面的元素不变。要求操作后的整个数组非递减,统计满足条件的 `k` 的数量。题目链接:https://ac.nowcoder.com/acm/contest/141721/C。时间复杂度:O(nlogn)

2501_94316951的博客 172

【数据结构-3】算法美学之降复杂度

在while循环的循环体内,首先用临时变量保存最后一个位置的数据,再通过for循环把所有元素往后移动一位,最后把tmp中保存的值放到下标为0的位置上去。方法二的思路是:创建新数组,让原数组中后k个数据移动到新数组中前面的位置,让原数组中前numsSize-k个数据移动到新数组中后面的位置,这。这段代码的思路是:三次逆置,第一次逆置前numsSize-k个数据,第二次逆置后k个数据,最后整体逆置。这篇博文分享一道解法不一的算法题,求解过程的目的在于降低算法的时间复杂度,题源力扣。,属于空间换时间的操作。

weixin_44218929的博客 85

算法61,判定是否为字符重排

两字符串能互为重排 ⇔。

sheshibenniaodan的博客 219

算法日常・每日刷题--<动态规划>32

给定严格递增的正整数数组,求最长斐波那契子序列长度。使用二维DP,dp[i][j]表示以arr[i]、arr[j]为最后两项的序列长度,初始化均为2。通过哈希表快速查找前一项target = arr[j] - arr[i],若存在且下标小于i,则状态转移:dp[i][j] = dp[k][i] + 1。遍历更新全局最大长度,最终若结果小于3则返回0。时间复杂度O(n²),空间复杂度O(n²)。

2503_92261635的博客 178

算法札记:几何分布在算法题UVA1262的运用

集卡问题求解核心:将集齐n种优惠券的过程分为n个阶段,每个阶段期望购买次数为 $ \frac{n}{k} $(k为剩余种类数),总期望为 $ n \cdot H_n $(调和数)。通过自洽方程推导单阶段期望,无需几何分布或无穷级数,逻辑清晰且适用于大一水平。例如,n=5时期望约11.42,非5。题目要求以带分数形式输出精确结果,算法上需累加分数并化简。

Keven_11的博客 356

考拉兹猜想 - 7

本文通过引入虚数单位重构Collatz猜想的迭代逻辑,指出偶数减半与奇数“乘3加1”的过程在虚数坐标下等价于归结操作。关键在于:乘3加1使奇数跃升至偶数,随后持续减半,而虚数单位代表“无限减1”,实现无限向有限的转化。无论初始值如何,减半始终主导,最终归结为4-2-1循环。该视角消解了正向思维中的速度竞争疑虑,证明归结是必然结果。

杨铸人的博客 44

SSL证书选RSA还是ECDSA:公钥算法、CA签名与兼容性怎么核对

申请SSL证书时,RSA和ECDSA该怎么选?先分清站点公钥算法、CA签名算法和TLS实际兼容性,再用隔离OpenSSL实验读取两类材料,核对申请、续期和部署交接,避免只看Signature Algorithm就选错。

谁呀!的博客 400
上一篇: GDDR5X vs HBM3E:游戏显卡与AI服务器显存技术全解析(附性能实测对比)
下一篇: 旋转位置编码(RoPE)在长序列建模中的实践与优化
寂静夜空35
博客等级 码龄3年 59粉丝 1797原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值