《LeetCode 646 最长数对链 || LeetCode 1143 最长公共子序列》

一、题目

二、做题思路

2.1 状态表示(核心基础)

定义 dp[i] 表示以第 i 个数对结尾的最长数对链的长度 。由于数对可任意顺序选择,我们先按 left 升序排序,使得后续只需考虑 j < i 的前驱,具备无后效性。

2.2 状态转移方程(关键难点)

枚举前驱 j < i,若 pairs[i][0] > pairs[j][1] ,则可以将数对 i 接在数对 j 后面形成更长的链,长度为 dp[j] + 1。取所有合法 j 中的最大值:

dp[i] = max(dp[i], dp[j] + 1) (满足 pairs[i][0] > pairs[j][1])。

2.3 初始化(边界防护)

每个数对自身可构成长度为 1 的链,因此 dp[i] = 1 (对所有 i)。

2.4 填表顺序(递推方向)

dp[i] 依赖所有 j < i 的状态,因此 从左到右 遍历 i,内层遍历所有 j < i,确保前置状态已就绪。

2.5 返回值(目标映射)

取所有 dp[i] 中的最大值,返回该最大值。

三、代码

cpp 复制代码
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int n = nums.size();
        // 边界处理:空数组无摆动序列
        if (n == 0) return 0;

        // 1. 创建dp表
        // f[i] : 以 nums[i] 结尾,且最后一段比较关系为"上升"(nums[i-1] < nums[i])的摆动序列的最大长度
        // g[i] : 以 nums[i] 结尾,且最后一段比较关系为"下降"(nums[i-1] > nums[i])的摆动序列的最大长度
        // 初始化:每个元素自身可构成长度为 1 的摆动序列(既可以是上升也可以是下降的起点)
        vector<int> f(n, 1);
        vector<int> g(n, 1);

        // 2. 填表顺序:从左到右(i 从 1 到 n-1),因为 f[i]/g[i] 依赖所有 j < i 的状态
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                // 3. 状态转移方程:
                // 若 nums[i] > nums[j],则可以将 nums[i] 接在"下降"结尾的序列后面(g[j]),形成上升结尾的序列,
                // 长度 = g[j] + 1;同时保留 f[i] 原有的值(可能通过其他 j 得到更长的长度)
                if (nums[i] > nums[j]) {
                    f[i] = max(f[i], g[j] + 1);
                }
                // 若 nums[i] < nums[j],则可以将 nums[i] 接在"上升"结尾的序列后面(f[j]),形成下降结尾的序列,
                // 长度 = f[j] + 1;同时保留 g[i] 原有的值
                else if (nums[i] < nums[j]) {
                    g[i] = max(g[i], f[j] + 1);
                }
                // 若相等,无法构成摆动,跳过(状态保持不变)
            }
        }

        // 4. 返回值:所有 f[i] 和 g[i] 中的最大值
        int ret = 1;
        for (int i = 0; i < n; i++) {
            ret = max(ret, max(f[i], g[i]));
        }
        return ret;
    }
};

四、流程图

五、题目

六、做题思路

6.1 状态表示(核心基础)

本题要求返回两个字符串的最长公共子序列的长度 。定义 dp[i][j] 表示 text1 的前 i 个字符与 text2 的前 j 个字符的最长公共子序列长度。

6.2 状态转移方程(关键难点)

对于 text1[i] 和 text2[j](从1开始计数):

  • 若 text1[i] == text2[j] ,则当前字符可纳入公共子序列,长度 = dp[i-1][j-1] + 1。

  • 否则,取不包含 text1[i] 或不包含 text2[j] 的较大者,即 dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

6.3 初始化(边界防护)

dp[0][j] = dp[i][0] = 0,表示空串与任意串的公共子序列长度为 0,默认初始化为 0 即可。

6.4 填表顺序(递推方向)

dp[i][j] 依赖左上 dp[i-1][j-1]、上方 dp[i-1][j] 和左方 dp[i][j-1],因此 从上到下、从左到右 遍历 i 和 j,确保前置状态已就绪。

6.5 返回值(目标映射)

最终 返回 dp[n1][n2],即为两个完整字符串的最长公共子序列长度。

七、代码

cpp 复制代码
class Solution 
{
public:
    int longestCommonSubsequence(string text1, string text2) 
    {
        int n1 = text1.size();
        int n2 = text2.size();

        // 1. 创建dp表(多开一行一列,方便处理边界)
        // dp[i][j] 表示 text1 的前 i 个字符(text1[0..i-1])和 text2 的前 j 个字符(text2[0..j-1])的最长公共子序列长度
        vector<vector<int>> dp(n1 + 1, vector<int>(n2 + 1, 0));

        // 为了便于下标对齐,在字符串前面添加一个占位符(空格),
        // 这样 text1[i] 对应原 text1 的第 i-1 个字符(i 从 1 开始)
        text1 = ' ' + text1;
        text2 = ' ' + text2;

        // 2. 初始化:dp[0][j] = 0 和 dp[i][0] = 0(默认已初始化为 0)

        // 3. 填表顺序:从上到下(i 从 1 到 n1),从左到右(j 从 1 到 n2)
        //    因为 dp[i][j] 依赖于 dp[i-1][j-1]、dp[i-1][j]、dp[i][j-1](均在左上方、上方或左方),
        //    按行优先遍历即可保证依赖状态已计算。
        for (int i = 1; i <= n1; i++) 
        {
            for (int j = 1; j <= n2; j++) 
            {
                // 4. 状态转移方程:
                // 若当前两个字符相等,则当前 LCS 长度 = 左上角 dp[i-1][j-1] + 1
                if (text1[i] == text2[j]) 
                {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } 
                else 
                {
                    // 若不等,则取上方或左方中的较大值(即去掉 text1[i] 或 text2[j] 后的 LCS)
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 5. 返回值:dp[n1][n2] 即为两个字符串的最长公共子序列长度
        return dp[n1][n2];
    }
};

八、流程图

相关推荐
fpcc16 小时前
c++编程实践—堆和栈越界调试
c++
yi01116 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
weiabc17 小时前
MSYS2 UCRT64 + g++ C++ 中文输出乱码 完整全过程
c++
灯澜忆梦18 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下18 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J19 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛19 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有19 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu11111119 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS20 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密