常用算法里的细节

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

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

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

相关推荐
大爱编程♡21 小时前
C++基础-类和对象
c++·算法
ysa05103021 小时前
【板子】费用流
算法·深度优先·图论
玖玥拾21 小时前
LeetCode 80 删除有序数组中的重复项 II
算法·leetcode
青山木21 小时前
Hot 100 --- 电话号码的字母组合
java·数据结构·算法·leetcode·逻辑回归
闪电悠米21 小时前
力扣hot100-240.搜索二维矩阵2-单调性剪枝详解
数据结构·算法·leetcode·矩阵·哈希算法
imuliuliang21 小时前
关于基于图论的最短路径算法性能对比分析7
算法
SilentSlot21 小时前
【C/C++】手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发
c语言·c++·tcp/ip
雨落在了我的手上1 天前
Java数据结构(九):栈和队列
java·开发语言·数据结构
SilentSlot1 天前
【C/C++】手写 DPDK 协议栈(六):TCP 三次握手、状态机与数据回显
c语言·c++·tcp/ip
乱七八糟的屋子1 天前
AMQP C++ 超详细实战教程(amqp-cpp 开源库从零入门到生产落地)
c++·rabbitmq·任务队列·amqp·流量削峰·c++服务端异步解耦·分布式消息通信