C++实现最长公共子序列(LCS):动态规划算法详解

晚来风
晚来风
发布时间:2026-10-15| 5人浏览过
原创

本文介绍如何使用C++结合动态规划技术高效解决最长公共子序列(LCS)问题。文章拆解了二维状态表的构建逻辑与路径回溯过程,提供可直接运行的完整代码示例,并分析了时间空间复杂度。

算法核心原理

最长公共子序列(Longest Common Subsequence, LCS)旨在找出两个字符串中共同拥有的、长度最长的子序列。该问题不适合使用贪心算法,因为局部最优选择往往导致全局非最优,而动态规划可以通过记录子问题的解来避免重复计算。

算法依赖两个关键矩阵:

  • 长度矩阵 (num):num[i][j] 表示字符串A的前i个字符与字符串B的前个字符的LCS长度。
  • 方向标记矩阵 (flag):用于回溯构造具体的子序列。
    • 1:对角线方向,表示 A[i-1] == B[j-1],当前字符匹配成功,纳入子序列。
    • 2:水平向左,表示从左侧转移而来,B[j-1] 未匹配或无需考虑。
    • 3:竖直向上,表示从上方转移而来,A[i-1] 未匹配或无需考虑。

C++ 代码实现

以下代码实现了完整的动态规划填表与逆推打印功能。代码中使用全局数组简化内存管理,并在主函数中演示了标准用法。

#include <stdio.h>
#include <string.h>

// 定义最大字符串长度,根据实际项目需求调整
#define MAX_LEN 500

char a[MAX_LEN], b[MAX_LEN];
int num[MAX_LEN + 1][MAX_LEN + 1]; // 记录LCS长度的中间结果
int flag[MAX_LEN + 1][MAX_LEN + 1]; // 标记数组:1-斜向(匹配), 2-向右, 3-向下

void LCS();       // 核心动态规划求解
void getLCS();    // 逆向追踪并输出子序列

int main()
{
    // 初始化测试数据
    strcpy(a, "ABCBDAB");
    strcpy(b, "BDCABA");
    
    // 清零数组,防止干扰
    memset(num, 0, sizeof(num));
    memset(flag, 0, sizeof(flag));
    
    // 执行算法
    LCS();
    
    // 输出LCS长度
    printf("LCS Length: %d\n", num[strlen(a)][strlen(b)]);
    
    // 输出具体的LCS字符串
    printf("LCS Sequence: ");
    getLCS();
    printf("\n");
    
    return 0;
}

void LCS()
{
    int lenA = strlen(a);
    int lenB = strlen(b);
    
    for (int i = 1; i <= lenA; i++)
    {
        for (int j = 1; j <= lenB; j++)
        {
            // 注意:数组下标从1开始,对应字符串下标需减1
            if (a[i - 1] == b[j - 1]) 
            {
                num[i][j] = num[i - 1][j - 1] + 1;
                flag[i][j] = 1; // 匹配成功,记录对角线方向
            }
            else if (num[i][j - 1] > num[i - 1][j])
            {
                num[i][j] = num[i][j - 1];
                flag[i][j] = 2; // 来自左侧
            }
            else
            {
                num[i][j] = num[i - 1][j];
                flag[i][j] = 3; // 来自上方
            }
        }
    }
}

void getLCS()
{
    char res[MAX_LEN];
    int i = strlen(a);
    int j = strlen(b);
    int k = 0; // 结果数组指针
    
    while (i > 0 && j > 0)
    {
        if (flag[i][j] == 1)
        {
            // 匹配字符,加入结果栈(注意顺序是逆序的)
            res[k++] = a[i - 1];
            i--;
            j--;
        }
        else if (flag[i][j] == 2)
        {
            j--; // 向左移动
        }
        else
        {
            i--; // 向上移动
        }
    }
    
    // 逆序打印得到正序结果
    for (int p = k - 1; p >= 0; p--)
    {
        printf("%c", res[p]);
    }
}

运行结果与图示

对于输入字符串 a="ABCBDAB" 和 b="BDCABA",程序将计算出的LCS长度为4,并还原出其中一个可能的子序列(如 BCBA 或 BDAB)。下图展示了算法执行过程中的状态变化示意:

复杂度分析

  • 时间复杂度:O(M × N),其中 M 为字符串 A 的长度,N 为字符串 B 的长度。需要填充一个 M×N 的二维表。
  • 空间复杂度:O(M × N),用于存储 num 和 flag 矩阵。若仅需长度而不需回溯路径,可通过滚动数组优化至 O(min(M, N))。

以上就是C++动态规划实现查找最长公共子序列的详细内容,更多关于C++算法设计与动态规划技巧的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。