热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

每日算法挑战#5:最长公共子序列(LCS)优化解法

本题探讨如何在两个长度为n的整数序列中,找到它们的最长公共子序列(LCS)。题目保证第一个序列中的元素各不相同。我们将深入分析并提供一种高效的求解方法。

每日算法挑战 #5

最长公共子序列问题

给定两个长度为 n 的整数序列,目标是计算它们的最长公共子序列(LCS)的长度。特别地,第一个序列中的所有元素都是唯一的。

注意:

  • 第一个序列的所有元素均唯一。
  • 第二个序列中可能存在重复元素。
  • 一个序列中的某些元素可能不会出现在另一个序列中。

输入格式

第一行包含一个整数 n,表示序列的长度。

接下来两行,每行包含 n 个整数,分别代表两个整数序列。

输出格式

输出一个整数,表示最长公共子序列的长度。

数据范围

1 ≤ n ≤ 1,000,000, 序列内元素取值范围 [1, 1,000,000]。

输入样例1:

5
1 2 3 4 5
1 2 3 4 5

输出样例1:

5

输入样例2:

5
1 2 3 5 4
1 2 3 4 5

输出样例2:

4

++++

思路解析:最初看到这个问题时,可能会认为它是一个简单的动态规划(DP)问题。然而,考虑到数据范围较大,直接使用 DP 方法并不高效。关键在于利用第一个序列中元素的唯一性,这使得我们可以将问题转化为寻找最长递增子序列(LIS)的问题。

具体来说,我们可以构建一个辅助数组 tar,记录第二个序列中每个元素在第一个序列中的位置。例如,在输入样例2中:

序列1:1 2 3 5 4

序列2:1 2 3 4 5

tar数组:1 2 3 5 4

我们观察到,tar 数组中的每个数字代表的是位置下标。如果我们在 tar 数组中找到最长递增子序列的长度,那么这个子序列在第一个序列中的相对顺序也是递增的。因此,原问题可以转化为求 tar 数组的 LIS。

由于 n 的范围较大([1, 1,000,000]),我们不能使用 O(n²) 的 DP 方法来求解 LIS。相反,应该采用基于贪心和二分查找的 O(n log n) 解法。

以下是具体的 C++ 实现代码:

#include 
#include
#include
using namespace std;
const int N = 1000010;
int tar[N];
int n;
int q[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
tar[x] = i;
}
int len = 0;
// 基于贪心通过二分解决
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
int k = tar[x];
if (!k) continue; // 跳过未出现的数据
int l = 0, r = len;
while (l int mid = l + r + 1 >> 1;
if (q[mid] else r = mid - 1;
}
len = max(len, r + 1);
q[r + 1] = k;
}
printf("%d\n", len);
return 0;
}

推荐阅读
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本题探讨了一种字符串变换方法,旨在判断两个给定的字符串是否可以通过特定的字母替换和位置交换操作相互转换。核心在于找到这些变换中的不变量,从而确定转换的可能性。 ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • C++: 实现基于类的四面体体积计算
    本文介绍如何使用C++编程语言,通过定义类和方法来计算由四个三维坐标点构成的四面体体积。文中详细解释了四面体体积的数学公式,并提供了两种不同的实现方式。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 文件描述符、文件句柄与打开文件之间的关联解析
    本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • Java 类成员初始化顺序与数组创建
    本文探讨了Java中类成员的初始化顺序、静态引入、可变参数以及finalize方法的应用。通过具体的代码示例,详细解释了这些概念及其在实际编程中的使用。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • C++构造函数与初始化列表详解
    本文深入探讨了C++中构造函数的初始化列表,包括赋值与初始化的区别、初始化列表的使用规则、静态成员初始化等内容。通过实例和调试证明,详细解释了初始化列表在对象创建时的重要性。 ... [详细]
  • 本文详细介绍了C语言中链表的两种动态创建方法——头插法和尾插法,包括具体的实现代码和运行示例。通过这些内容,读者可以更好地理解和掌握链表的基本操作。 ... [详细]
author-avatar
xsf9507
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有