常用算法里的细节

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

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

你好,我是会编程的土豆,一名热爱后端技术的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数组就是记录最长子序列元素的数组,而且是保证里面的每个值尽可能小;

相关推荐
Logic1016 小时前
C语言/数据结构位运算题解:异或XOR找出弹子游戏机中数量为奇数的数字——只出现奇数次
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
147API6 小时前
如何设计“回答、追问、停答”三类蒸馏训练集
人工智能·算法·机器学习
朝朝辞暮i6 小时前
C++ 第 10 课:函数 Function
开发语言·c++
Zootopia6266 小时前
快递无人车与无人机各自进入配送网络后,路线能否一起算?
c++·人工智能·机器学习·matlab·ai·机器人·无人机
朝朝辞暮i6 小时前
C++ 第7课 while 循环
开发语言·c++·算法
blxr_7 小时前
力扣hot100爬楼梯https://leetcode.cn/problems/climbing-stairs/
算法·leetcode·职场和发展
pride.li7 小时前
ISP标定-NR标定(Noise Reduction,降噪校准)
算法·计算机视觉·isp
CQU_JIAKE7 小时前
9.29【A】
算法·深度优先
没落之王8 小时前
AI在文言文——论文脉复苏对AI的意义
大数据·人工智能·算法
huanbailu8 小时前
Qt 跨线程信号槽:connect 返回 true 但槽函数不执行的坑
开发语言·c++·qt·信号槽·跨线程·元类型