常用算法里的细节

👨‍💻 关于作者:会编程的土豆

"不是因为看见希望才坚持,而是坚持了才看见希望。"

你好,我是会编程的土豆,一名热爱后端技术的Java学习者。

📚 正在更新中的专栏:

💕作者简介:后端学习者

LCS模版(最长公共子序列(Longest Common Subsequence))

仅求长度

  • 若字符相等:dp[i][j] = dp[i-1][j-1] + 1

  • 若字符不等:dp[i][j] = max(dp[i-1][j], dp[i][j-1])

cpp 复制代码
int longestCommonSubsequence(string text1, string text2) {
    int n = text1.size(), m = text2.size();
    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
    
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (text1[i - 1] == text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[n][m];
}

这里注意因为i,j记录的是前s的i个字符和t的前j个字符中的公共子序列,由于字符下标是从0开始的,所以实际上i只记录到下标为i-1的数,j也是同理;所以if对比的时候记得是对比si-1==tj-1;记得要减一;

回溯具体子序列

在 DP 填表完成后,从右下角 (n, m) 倒推回去

cpp 复制代码
string getLCS(string text1, string text2) {
    int n = text1.size(), m = text2.size();
    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
    
    // 1. 填表
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (text1[i - 1] == text2[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    }
    
    // 2. 回溯构建 LCS 字符串
    string lcs;
    int i = n, j = m;
    while (i > 0 && j > 0) {
        // 如果字符相等,它是LCS的一部分,往左上移动
        if (text1[i - 1] == text2[j - 1]) {
            lcs.push_back(text1[i - 1]);
            i--;
            j--;
        } 
        // 如果不相等,走向数值较大的那个方向
        else if (dp[i - 1][j] > dp[i][j - 1]) {
            i--;
        } else {
            j--;
        }
    }
    
    reverse(lcs.begin(), lcs.end());
    return lcs;
}

LIS(最长上升子序列(Longest Increasing Subsequence, LIS))

这个是求一个字符串中或者数组中最长上升的那个子序列;

元素可以一样的用upper_bound

cpp 复制代码
vector<int>tail;
for (int i = 0; i < arr.size(); i++)
{
	int x = arr[i];
	auto it = upper_bound(tail.begin(), tail.end(), x);
	if (it == tail.end())
	{
		tail.push_back(x);
	}
	else *it = x;
}
cout << tail.size() << endl;

这个是求arr数组的最长可以一样元素的最长子序列;

元素不可以一样的用lower_bound

cpp 复制代码
vector<int>tailb;
for (int i = 0; i < arr.size(); i++)
{
	int x = arr[i];
	auto it = lower_bound(tailb.begin(), tailb.end(), x);
	if (it == tailb.end())
	{
		tailb.push_back(x);
	}
	else *it = x;
}
cout << tailb.size() << endl;

这个是求arr数组的最长子序列,必须严格递增;

你想要的子序列类型 应该用的函数 原因
严格递增(不能相等) lower_bound 找第一个 >= x 的位置,会替换掉相等的元素,阻止重复
非严格递增(允许相等) upper_bound 找第一个 > x 的位置,保留相等的元素,允许重复

注意里面的操作都是关于tail数组的操作,tail数组就是记录最长子序列元素的数组,而且是保证里面的每个值尽可能小;

相关推荐
csdn_aspnet18 分钟前
C++ 3个有序点的方向(Orientation of 3 ordered points)
c++·算法
赤生云电竞42 分钟前
GPU算力共享平台架构实践:任务分发与资源隔离的关键配置
算法·架构·gpu算力
小七在进步1 小时前
string的使用(2)
c++
青少儿编程课堂2 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
wo_jack4 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
Oneshot4 小时前
DLX(Dancing Links)算法详解:求解数独最快的算法
算法
青少儿编程课堂5 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
kongdong5 小时前
Hikyuu | RSI均值回归交易策略实现
算法·均值算法·回归·量化交易·交易策略·hikyuu
小王C语言5 小时前
优选算法:分治-归并排序
算法
草莓熊Lotso5 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试