最长子序列问题:贪心与动态规划解法详解

发布时间:2026/10/31 17:04:35

最长子序列问题:贪心与动态规划解法详解 1. 题目背景与问题分析中山市2023年信息学奥林匹克竞赛题目永别题目编号B4336是一道考察选手对子序列问题理解和算法实现能力的题目。题目要求我们处理一个字符串找出满足特定条件的最长子序列。这类子序列问题在信息学竞赛中非常常见通常考察选手对动态规划、贪心算法等基础算法的掌握程度。题目名称永别可能暗示着需要处理字符串中某些字符的告别即删除或忽略情况。2. 题目理解与建模虽然题目具体描述未提供但根据常见竞赛题型和题目名称推测这可能是一个关于字符串中子序列处理的题目。常见的形式包括寻找最长回文子序列删除最少字符使字符串满足特定条件统计满足条件的子序列数量假设题目要求是给定一个字符串找出不包含连续相同字符的最长子序列。例如 输入aab 输出2可以取ab3. 算法设计与选择3.1 暴力解法分析最直观的方法是枚举所有可能的子序列然后检查每个子序列是否满足条件。对于一个长度为n的字符串子序列数量为2^n时间复杂度为O(2^n)显然不适用于大规模数据。3.2 贪心算法思路观察发现当遇到连续相同字符时我们只需要保留其中一个即可。这提示我们可以使用贪心算法初始化结果子序列为空遍历字符串对于每个字符如果与结果子序列最后一个字符不同则加入否则跳过返回结果子序列的长度这种方法时间复杂度为O(n)空间复杂度为O(1)如果只计算长度。3.3 动态规划解法虽然贪心算法更高效但为了展示更通用的解法我们可以考虑动态规划定义dp[i]表示以第i个字符结尾的最长子序列长度。状态转移方程为dp[i] dp[i-1] 1 如果s[i] ! s[i-1]dp[i] dp[i-1] 如果s[i] s[i-1]最终结果为dp[n-1]。4. C代码实现4.1 贪心算法实现#include iostream #include string using namespace std; int longestGoodSubsequence(string s) { if (s.empty()) return 0; int count 1; for (int i 1; i s.size(); i) { if (s[i] ! s[i-1]) { count; } } return count; } int main() { string input; cin input; cout longestGoodSubsequence(input) endl; return 0; }4.2 动态规划实现#include iostream #include vector #include string using namespace std; int longestGoodSubsequenceDP(string s) { if (s.empty()) return 0; vectorint dp(s.size(), 1); for (int i 1; i s.size(); i) { if (s[i] ! s[i-1]) { dp[i] dp[i-1] 1; } else { dp[i] dp[i-1]; } } return dp.back(); } int main() { string input; cin input; cout longestGoodSubsequenceDP(input) endl; return 0; }5. 算法优化与比较5.1 空间优化动态规划版本可以优化空间复杂度因为dp[i]只依赖于dp[i-1]int longestGoodSubsequenceDPOpt(string s) { if (s.empty()) return 0; int prev 1; for (int i 1; i s.size(); i) { if (s[i] ! s[i-1]) { prev; } } return prev; }5.2 性能对比贪心算法O(n)时间O(1)空间动态规划O(n)时间O(n)空间可优化为O(1)虽然两种方法在时间复杂度上相同但贪心算法更直观且常数因子更小是本题的更优解。6. 边界条件与测试用例6.1 常见测试用例void test() { assert(longestGoodSubsequence(aab) 2); assert(longestGoodSubsequence(aaabbb) 2); assert(longestGoodSubsequence(abcabc) 6); assert(longestGoodSubsequence() 0); assert(longestGoodSubsequence(a) 1); assert(longestGoodSubsequence(ababab) 6); }6.2 特殊边界情况空字符串单字符字符串全相同字符的字符串已满足条件的字符串无连续相同字符7. 竞赛技巧与注意事项理解题意仔细阅读题目描述确保理解所有条件和要求样例分析手动计算给定的样例验证理解是否正确算法选择根据数据规模选择合适的算法本题n可能很大排除O(n^2)以上算法代码简洁竞赛中时间宝贵尽量写简洁明了的代码边界检查特别注意空输入、单元素等边界情况变量命名使用有意义的变量名避免比赛后期混淆8. 类似题目拓展最长递增子序列LIS经典DP问题最长公共子序列LCS两个字符串的匹配问题最长回文子序列需要更复杂的DP状态设计删除字符使字符串平衡类似但条件不同的题目9. 性能测试与分析对于最大规模测试n1e6贪心算法约10ms现代CPU动态规划未优化可能因内存分配稍慢动态规划优化后与贪心相当实际竞赛中两者都可接受但贪心算法更值得推荐。10. 常见错误与调试off-by-one错误循环起始和结束条件空指针访问未检查字符串是否为空初始化错误count或dp数组初始值不正确字符比较错误误用代替输出格式错误多输出或少输出内容调试建议使用小样例手动模拟添加中间变量输出使用assert进行验证11. 算法正确性证明贪心算法的正确性基于以下观察最优解必然包含至少一个连续相同字符组中的一个字符选择保留最后一个不会影响后续选择因此局部最优选择导致全局最优解动态规划的正确性则由最优子结构保证问题的最优解包含子问题的最优解。12. 复杂度理论分析贪心算法时间单次遍历O(n)空间常数个变量O(1)动态规划时间单次遍历O(n)空间未优化O(n)优化后O(1)两种方法在最坏情况下都需要检查每个字符因此时间复杂度下界为Ω(n)。13. 实际应用场景这类子序列问题在实际中有多种应用DNA序列分析文本差异比较数据压缩版本控制系统拼写检查与自动更正理解这类算法有助于解决更复杂的字符串处理问题。14. C语言特性利用本题解中利用了以下C特性STL string方便处理字符串引用传递避免不必要的拷贝vector动态规划表实现范围for循环C11更简洁的遍历assert测试验证在竞赛中熟练掌握这些特性可以提升编码效率。15. 输入输出优化对于极端大规模数据如n1e6可以考虑IO优化ios::sync_with_stdio(false); cin.tie(nullptr);这可以显著提高cin/cout的速度但注意不能再混用C和C的IO函数。16. 多语言实现对比作为对比Python实现可能如下def longest_good_subsequence(s): if not s: return 0 count 1 for i in range(1, len(s)): if s[i] ! s[i-1]: count 1 return countPython版本更简洁但运行速度较慢不适合竞赛中的大规模数据。17. 算法可视化理解想象字符串为彩色珠子项链贪心算法就是跳过连续同色珠子动态规划则是记录到每颗珠子时的最长链这种可视化有助于理解算法本质。18. 数学归纳法证明使用数学归纳法证明贪心算法正确性基本情况n1时显然成立归纳假设对于长度k的字符串成立归纳步骤对于k1长度根据最后一个字符是否与前一个相同结果要么加1要么不变因此算法对所有n都成立。19. 递归解法及其局限虽然可以用递归表达int helper(string s, int pos, char last) { if (pos s.size()) return 0; if (s[pos] ! last) return 1 helper(s, pos1, s[pos]); return helper(s, pos1, last); }但递归深度为O(n)可能栈溢出且效率低于迭代版本。20. 竞赛策略总结快速理解题意明确输入输出分析样例验证理解选择合适算法考虑时间空间复杂度编写简洁代码注意边界条件测试各种情况包括极端案例如有时间考虑更优解或替代解法对于本题贪心算法是最佳选择兼具效率和简洁性。
延伸阅读

更多相关文章

2026/10/31 17:04:35

AI提示词身份设定指南:用角色扮演提升大模型输出质量

1. 为什么“给 AI 一个身份”能直接拉高输出质量 很多人用 AI 的方式,其实跟使唤一个刚进公司的实习生差不多——上来就丢一句“帮我写个方案”,然后抱怨它写得空、写得泛、写得像百度百科。问题不在模型笨,在于你没告诉它“你是谁”。 我做…

2026/10/31 18:04:37

SpringBoot考研互助平台开发实践与架构解析

1. 项目背景与核心价值考研备考是一场持久战,很多考生在这个过程中会遇到各种问题:资料获取困难、学习进度难以把控、疑难问题无人解答、备考压力无处释放。传统的考研论坛和QQ群已经难以满足当下考生的需求——前者功能单一缺乏互动性,后者信…

2026/10/31 18:04:37

PostgreSQL 15 shared_buffers参数优化指南

1. PostgreSQL 15中的shared_buffers参数解析shared_buffers是PostgreSQL中最重要的内存配置参数之一,它定义了数据库服务器用于缓存数据的内存区域大小。这个参数直接影响到数据库的查询性能和整体吞吐量。在PostgreSQL 15中,这个参数的配置方式与之前版…

2026/10/31 18:04:37

Oracle APEX 4.2.5 开发实战:环境搭建与表单动态交互

简介:《Oracle APEX深入浅出》是一份面向Oracle APEX初学者与中级开发者的技术文档,侧重解决从环境搭建到企业级应用开发中的知识断层问题。资源为单个doc文档,压缩包约8.11MB,内容以开发指南形式组织,适合作为系统学习…

2026/10/31 18:04:37

GDPO与VideoAuto-R1:多目标强化学习与视频推理的技术突破

1. 论文核心内容解析:GDPO与VideoAuto-R1的技术突破 1.1 GDPO:多奖励强化学习的解耦归一化策略 在多目标强化学习场景中,传统方法通常采用加权求和的方式处理多个奖励信号。这种简单粗暴的合并方式存在三个致命缺陷: 不同奖励量…

2026/10/31 17:59:37

技术直播拆解:硬核知识可视化与信任经济新形态

1. 雷军拆车直播现象解析5小时不间断的汽车拆解直播,这个看似硬核枯燥的内容形式却在雷军的操盘下成为现象级传播案例。这场直播之所以能够突破圈层引发广泛讨论,关键在于它精准抓住了当前内容市场的三个核心痛点:硬核知识的可视化呈现&#…

2026/10/30 20:55:10

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/30 20:55:10

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/30 20:55:09

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/31 0:02:41

猫狗目标检测数据集:VOC/COCO/YOLO三格式一体化实战包

简介:本资源是一套面向计算机视觉初学者与YOLO目标检测实践者的猫狗图像数据集及配套开发工具包,专为快速上手目标检测模型训练而设计。资源包含1000张真实场景高清猫狗图片,标注质量高,同时提供VOC(XML)、…

2026/10/31 0:02:41

HDU2017多校标程复现:算法竞赛工程化真题沙盒

简介:本资源为2017年HDU多校联合训练第一场官方配套资料,面向ACM程序设计竞赛备赛学生、算法爱好者及高校编程集训队成员,旨在提供权威解题参考与完整测试验证环境。压缩包共40个文件,含15份C标程(覆盖全部赛题&#x…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑