面试算法题精讲:最长回文子序列

排序算法与动态规划空间压缩:面试高频题精讲 排序算法与动态规划是算法面试的两大基石。快速排序的分治思想、归并排序的稳定性、堆排序的TopK应用,构成了排序题的核心框架;而动态规划的空间压缩,则通过滚动数组分析状态依赖,将0-1背包、LCS等问题的空间复杂度从二维降至一维。理解这些原理不仅能应对面试中的变形题,还能迁移到工程实践——从MySQL的ORDER BY实现到Redis有序集合的底层设计,都离不开对排序与时空取舍的理解。本文从基础概念出发,梳理排序面试题的常见变形与动态规划空间压缩的思维跃迁,帮助读者构建从'能写出来'到'能写好'的算法能力。 阅读详情

面试算法题精讲:最长回文子序列

题目来源:516. 最长回文子序列

题目描述:

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

解法1:记忆化搜索

代码:

/*
 * @lc app=leetcode.cn id=516 lang=cpp
 *
 * [516] 最长回文子序列
 */

// @lc code=start

// 记忆化搜索

class Solution
{
public:
    int longestPalindromeSubseq(string s)
    {
        int n = s.length();
        int memo[n][n];
        memset(memo, -1, sizeof(memo)); // -1 表示还没有计算过
        
        function<int(int, int)> dfs = [&](int i, int j) -> int
        {
            if (i > j)
                return 0;
            if (i == j)
                return 1;
            int &res = memo[i][j];
            if (res != -1)
                return res;
            if (s[i] == s[j])
            {
                res = dfs(i + 1, j - 1) + 2;
                return res;
            }
            res = max(dfs(i + 1, j), dfs(i, j - 1));
            return res;
        };

        return dfs(0, n - 1);
    }
};
// @lc code=end

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n2),其中 n 为字符串 s 的长度。

空间复杂度:O(n2),其中 n 为字符串 s 的长度。

解法2:动态规划

代码:

/*
 * @lc app=leetcode.cn id=516 lang=cpp
 *
 * [516] 最长回文子序列
 */

// @lc code=start

// 动态规划

class Solution
{
public:
    int longestPalindromeSubseq(string s)
    {
        int n = s.length();
        // dp[i][j] 表示 s[i...j] 的最长回文子序列长度
        vector<vector<int>> dp(n, vector<int>(n, 0));
        // 初始化
        for (int i = 0; i < n; i++)
            dp[i][i] = 1;
        // 状态转移
        for (int i = n - 1; i >= 0; i--)
            for (int j = i + 1; j < n; j++)
            {
                if (s[i] == s[j])
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                else
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
            }
        return dp[0][n - 1];
    }
};
// @lc code=end

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n2),其中 n 为字符串 s 的长度。

空间复杂度:O(n2),其中 n 为字符串 s 的长度。

解法3:动态规划:空间优化

利用滚动数组可以优化空间复杂度。

代码:

// 动态规划:空间优化

class Solution
{
public:
    int longestPalindromeSubseq(string s)
    {
        int n = s.length();
        // 滚动数组
        vector<int> dp(n, 0);
        // 状态转移
        for (int i = n - 1; i >= 0; i--)
        {
            dp[i] = 1;
            int pre = 0; // dp[i+1][i]
            for (int j = i + 1; j < n; j++)
            {
                int tmp = dp[j];
                if (s[i] == s[j])
                    dp[j] = pre + 2;
                else
                    dp[j] = max(dp[j], dp[j - 1]);
                pre = tmp;
            }
        }
        return dp[n - 1];
    }
};

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n2),其中 n 为字符串 s 的长度。

空间复杂度:O(n),其中 n 为字符串 s 的长度。

解法4:转化成最长公共子序列问题

翻转字符串s为ss,我们发现问题转换为求s和ss的最长公共子序列的长度。

代码:

class Solution
{
private:
    int LCS(string s, string t)
    {
        int n = s.length(), m = t.length();
        int memo[n][m];
        memset(memo, -1, sizeof(memo)); // -1 表示没有访问过
        function<int(int, int)> dfs = [&](int i, int j) -> int
        {
            if (i < 0 || j < 0)
                return 0;
            int &res = memo[i][j];
            if (res != -1)
                return res;
            if (s[i] == t[j])
                return res = dfs(i - 1, j - 1) + 1;
            return res = max(dfs(i - 1, j), dfs(i, j - 1));
        };
        return dfs(n - 1, m - 1);
    }

public:
    int longestPalindromeSubseq(string s)
    {
        string s_rev(s.rbegin(), s.rend());
        return LCS(s, s_rev);
    }
};

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(n2),其中 n 为字符串 s 的长度。

空间复杂度:O(n2),其中 n 为字符串 s 的长度。

2026年CSP-S复赛真题及题解:T4【研发基地】 阅读详情

相关推荐

面向网络攻击行为可视化分析系统实现【WebSocket + 可视化】

本系统主要应用于网站运维管理,它解决了网站运维人员排查网络攻击行为复杂且繁琐等问题,提高了运维人员网络安全分析的效率和准确性。

oNew_Lifeo的博客 1622

暴力递归转动态规划(七)

暴力递归转动态规划

weixin_43936962的博客 204

Pyinstaller 打包 Pyzbar 时缺失 DLL 文件的排查与修复指南

本文详细解析了使用Pyinstaller打包Pyzbar库时,因缺失关键DLL文件导致程序闪退的常见问题。文章提供了从问题复现、错误诊断到最终修复的完整解决方案,核心在于通过修改.spec配置文件,手动将缺失的libzbar-64.dll等文件添加到打包过程中,确保生成的可执行文件能独立运行。

wdx012345的博客 504

【算法】动态规划—最长回文子序列

关于”回文串“的问题,是面试中常见的,本文提升难度,讲一讲”最长回文子序列“问题,题目很好理解:输入一个字符串 s,请找出 s 中的最长回文子序列长度。比如输入 s="aecda",算法返回3,因为最长回文子序列是 "aca",长度是3。。一定要记住这个定义才能理解算法。为什么这个问题要这样定义二维的 dp 数组呢?,这样定义容易归纳,容易发现状态转移关系。

qq_58023907的博客 1197

BUUCTF逆向题Youngter-drive

其实线程一代码我自己也不大理解,看了正确的 flag 后,我自己推出来的是这样:在 couece 中取出字符,然后在 QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm 中找出一样的,取出该字符在 QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm 中的下标,如果取出的字符是大写则 在ASCII中找出【下标 - 38】值对应的字符替换couece中的字符,同理,小写就减 96。

于高山之巅,方见大河奔涌;于群峰之上,更觉长风浩荡。 1098

手机拍照也能玩高光谱?教你用TensorFlow Lite在Android上实现实时RGB转高光谱

本文介绍了如何利用TensorFlow Lite在Android设备上实现实时RGB到高光谱的图像重构技术。通过深度学习模型优化和移动端部署策略,使智能手机具备专业级光谱分析能力,适用于农业检测、化妆品分析等多个领域。

weixin_29091105的博客 247

每周技术面试高频题汇总:大厂面试官到底在考什么?完整实战指南

大家好,又到了每周的面试复盘时间。。现在的面试官更喜欢把你扔进一个具体的“场景”里,看你怎么思考、怎么权衡(Trade-off)。基于过去一周 优快云、掘金、LeetCode 等社区的热议内容,我为大家精选了,涵盖算法、系统设计、数据库和网络四大领域。咱们不整那些虚的,直接上干货,看看这些题目背后的考察点和解题思路。

热爱技术与前沿创新,深耕科技领域,在科创中精进自我;探索技术乐趣,分享技术干货与成长心得,以技术为伴,热爱生活,在科创与生活中双向成长。 485

突破边缘AI算力瓶颈:YOLOv12模型剪枝与知识蒸馏联合优化全攻略

这套剪枝-蒸馏联合方案的优势在于其系统性和可靠性。它不是单一的技巧,而是一套完整的工程流程,确保了从研发到部署的无缝衔接。

m0_71589036的博客 219

动态规划算法:面试核心技巧与剑指Offer实战

动态规划是解决最优化问题的经典算法范式,其核心思想是通过状态转移方程将复杂问题分解为重叠子问题。在算法设计与性能优化中,动态规划能显著降低时间复杂度,例如将O(n²)暴力解法优化为O(n)线性解。该技术广泛应用于路径规划、资源分配、序列分析等场景,尤其在技术面试中成为考察候选人算法能力的重要标尺。以《剑指Offer》高频考题为例,动态规划解题需掌握状态定义、转移方程和空间优化三要素,其中滚动数组和降维处理是常见的工程优化手段。理解连续子数组最大和、青蛙跳台阶等经典问题,有助于快速识别问题中的最优子结构特征。

weixin_34161029的博客 436

使用YubiKey进行全盘加密、加密启动分区以及利用UEFI安全启动的详细指南

在本教程中,我们将使用YubiKey来增强电脑的安全性,通过加密整个硬盘,确保只有持有正确YubiKey的人才能访问。UEFI安全启动是一种在UEFI固件级别实施的安全标准,确保计算机仅启动签名的启动加载程序。为了符合您的要求,我将以此方式分配内容,确保每部分都有详尽的说明和代码。现在,您已经成功地使用YubiKey设置了全盘加密,并使用UEFI安全启动为系统增加了额外的安全层。注意:为了简洁和清晰,本文中的代码可能不是最优的或最完整的实现。注意:为了简洁和清晰,本文中的代码可能不是最优的或最完整的实现。

qq_38334677的博客 1006

基于STM32L4XX、HAL库的MP2672GD-0000-Z充电芯片驱动程序设计

CHG_STAT_GPIO_Port, CHG_STAT_Pin, // 这些宏应由 CubeMX 生成在 main.h。

zhusl6688的博客 497

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 333

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 606

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 422

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

优选算法:分治-归并排序

交易逆序对的总数

Wangshijie1015的博客 148

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 24

栈和队列和数组-优快云博客

一句话理解:栈就像一个羽毛球桶或手枪弹夹——只能从一头放、从一头取,最后放进去的最先拿出来。严格定义:栈是限定仅在某一端进行插入或删除操作的线性表。允许插入和删除的一端叫栈顶(top);另一端叫栈底(bottom);不含任何元素的栈叫空栈;栈中元素遵循后进先出(LIFO,Last In First Out)。两个核心动作插入数据叫入栈 / 进栈(Push);删除数据叫出栈(Pop)。⚠️ 易错点:栈只能在一端操作,不是两端。判断题里说「栈允许在两端操作」一定是错的。一句话理解。

2501_93853322的博客 171

Linux epoll 一篇讲透:从 select/poll 到红黑树、LT/ET,再到完整 TCP 服务器

一万个客户端已经连上服务器,眼下只有十个客户端发来了数据。服务器怎样把时间花在这十个连接上?理解这个问题,就抓住了 epoll 的主线。接下来,我们沿着“为什么需要它 → 接口怎么用 → 内核如何实现 → LT/ET 怎么写 → 完整服务器怎么运行”的顺序,把知识连起来。**阅读基础:**了解socketbindlistenaccept的基本用途即可。本文示例面向 Linux,服务器使用 C++17,实验脚本使用 Python 3。

2601_94861874的博客 452

从决策树到随机森林:Python机器学习里的“树形家族“深度实战与原理拆解

文章浏览阅读2.4k次,点赞52次,收藏32次。决策树和随机森林作为机器学习中的经典算法,各有优劣。决策树以其高可解释性和快速训练的特点

2601_96798011的博客 252

红黑树插入:三步与验证

红黑树是一种近似平衡的二叉搜索树,通过颜色规则(节点非红即黑、根为黑、红节点子节点为黑、每路径黑节点数相同)保证高度不超过 $2\log_2(N+1)$,实现 $O(\log n)$ 的查找、插入与删除。插入时新节点默认红色,仅当父节点为红时才需修复:叔红则染色上移,叔黑则通过单旋或双旋调整,并确保新根为黑。旋转操作需正确维护父子指针关系,避免断链。最终通过验证根非红、各路径黑节点数一致来确保结构合法。

ttxx__的博客 183

算法日常・每日刷题--<动态规划>32

给定严格递增的正整数数组,求最长斐波那契子序列长度。使用二维DP,dp[i][j]表示以arr[i]、arr[j]为最后两项的序列长度,初始化均为2。通过哈希表快速查找前一项target = arr[j] - arr[i],若存在且下标小于i,则状态转移:dp[i][j] = dp[k][i] + 1。遍历更新全局最大长度,最终若结果小于3则返回0。时间复杂度O(n²),空间复杂度O(n²)。

2503_92261635的博客 181

教育代码部队第196轮(A–G)题解合集

反过来,若能找到 k+1 个不同的原始数字,其和恰好为 S,那么保留其中一个作为 x、删去其余 k 个数字,就能使剩余数字总和等于 x。对当前 i,把所有满足 first[j]>r_i 的顶点位置加入树状数组,然后查询 [l_i,r_i] 的已加入数量。对每个 i≥2,给出区间 [l_i,r_i],从区间内每个 j 向 i 连边,即 j→i。反过来,若 j→i 存在替代路径,替代路径的第一步只能到某个 k,满足 j<k≤r_i(所有路径都严格向较大编号移动,最后必须从 [l_i,r_i] 进入 i)。

2301_79475922的博客 215

RPA、APA与AI Agent有什么区别?流程编排、动态规划与自动化执行机制解析

Agent用谁的账号操作?可以调用哪些工具?支付、删除和审批等敏感操作能否强制人工确认?执行过程是否留痕?一旦出现异常,能否及时暂停?这些要求对RPA、APA和企业智能体都适用,只是随着AI能够自主规划和选择工具,企业需要管理的执行范围也会相应扩大。因此,选型时可以直接拿一条真实业务流程测试:既看正常任务完成得怎么样,也看遇到异常时系统如何处理,以及运行一个月后维护起来是否方便。

GJGCY的博客 117

机器学习算法讲义——线性回归、逻辑回归、决策树

比喻:先给样本打出一个综合分数,再通过Sigmoid函数这个压缩器,把分数映射到0~1之间,输出结果代表是正样本的概率。损失函数用来衡量模型预测结果和真实标签之间的整体偏差,模型训练的目标就是不断调整参数,让MSE尽可能变小。比喻:专门针对概率设计的扣分规则,当真实标签和模型预判的概率相差很大时,会给予很重的惩罚。❌ 缺点:决策边界是线性的,面对交错分布的复杂样本效果有限,比较依赖前期的特征工程。比喻:相当于一套扣分标准,预测和真实值差距越大扣分越多,严重的错误会被加重惩罚。❌ 缺点:单树方差大、不稳定;

Michelle8023的博客 221

别让收藏夹替你学习:我搭AI知识体系的完整方法,脚本直接拿去用

面对知识碎片化困境,作者总结出一套“以工程思维管理学习”的六步法:画知识地图明确依赖关系,记学习日志量化投入,建笔记、做卡片、跑体检、讲出来闭环输出。通过地图定位学习路径,日志避免自我欺骗,最终实现知识成网、查漏补缺、高效复用。核心理念:学习不是刷课,而是构建可迭代的个人知识体系。

优快云博客专家,领域包括但不限于:AI、大数据、Python、架构师,有合作、课程、问题、疑惑请私信博主 244
上一篇: 面试算法题精讲:最长回文子串
下一篇: 2024 年华为机考最新模拟题
UestcXiye
博客等级 码龄8年 9031粉丝 1306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值