【Android面试八股文】荣耀面试算法题: 输出一个给定的字符串的最长回文子序列及其长度!

news2025/1/18 9:08:15

文章目录

  • 一、真题链接
  • 二、如何解决
    • 2.1算法思路
    • 2.2 算法步骤
    • 2.3 Java算法实现

一、真题链接

还好我以前刷过这道题,

其实题目就是LeetCode的 516.最长回文子序列,

地址:https://leetcode.cn/problems/longest-palindromic-subsequence/description/
在这里插入图片描述
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

  • 示例 1:

    • 输入:s = “bbbab”
    • 输出:4
    • 解释:一个可能的最长回文子序列为"bbbb"
  • 示例 2:

    • 输入:S = “cbbd”
    • 输出:
    • 解释:一个可能的最长回文子序列为"bb"
  • 提示:

    • 1 <= s.length <= 1000。
    • s仅由小写英文字母组成

二、如何解决

为了找到一个给定字符串的最长回文子序列及其长度,我们可以使用动态规划(DP)算法。下面是详细的算法步骤和Java实现:

2.1算法思路

作者:labuladong
链接:https://leetcode.cn/problems/longest-palindromic-subsequence/solutions/67456/zi-xu-lie-wen-ti-tong-yong-si-lu-zui-chang-hui-wen/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

定义一个二维dp数组

int n = arr.length;
int[][] dp = new dp[n][n];

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        if (arr[i] == arr[j]) 
            dp[i][j] = dp[i][j] + ...
        else
            dp[i][j] = 最值(...)
    }
}

找状态转移需要归纳思维,说白了就是如何从已知的结果推出未知的部分,这样定义容易归纳,容易发现状态转移关系。

具体来说,如果我们想求 dp[i][j],假设你知道了子问题 dp[i+1][j-1] 的结果(s[i+1..j-1] 中最长回文子序列的长度),你是否能想办法算出 dp[i][j] 的值(s[i..j] 中,最长回文子序列的长度)呢?
在这里插入图片描述

可以!这取决于 s[i]s[j] 的字符:

如果它俩相等,那么它俩加上 s[i+1..j-1] 中的最长回文子序列就是 s[i..j] 的最长回文子序列:

在这里插入图片描述
如果它俩不相等,说明它俩不可能同时出现在 s[i..j] 的最长回文子序列中,那么把它俩分别加入 s[i+1..j-1] 中,看看哪个子串产生的回文子序列更长即可:

在这里插入图片描述

以上两种情况写成代码就是这样:

if (s[i] == s[j])
    // 它俩一定在最长回文子序列中
    dp[i][j] = dp[i + 1][j - 1] + 2;
else
    // s[i+1..j] 和 s[i..j-1] 谁的回文子序列更长?
    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

至此,状态转移方程就写出来了,根据 dp 数组的定义,我们要求的就是 dp[0][n - 1],也就是整个 s 的最长回文子序列的长度。

2.2 算法步骤

  1. 定义DP数组:设 dp[i][j] 表示字符串 s[i...j] 的最长回文子序列的长度。

  2. 初始化

    • 对于每个单字符子串,dp[i][i] = 1,因为单个字符本身就是回文子序列。
  3. 状态转移

    • 如果 s[i] == s[j],那么 dp[i][j] = dp[i + 1][j - 1] + 2
    • 如果 s[i] != s[j],那么 dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
  4. 边界条件:从小到大填表,确保所有子问题都已解决。

  5. 回溯找到最长回文子序列

    • dp[0][n-1] 开始,回溯字符串,找到对应的最长回文子序列。

2.3 Java算法实现

首先明确一下 base case,如果只有一个字符,显然最长回文子序列长度是 1,也就是 dp[i][j] = 1 (i == j)

因为 i 肯定小于等于 j,所以对于那些 i > j 的位置,根本不存在什么子序列,应该初始化为 0

另外,看看刚才写的状态转移方程,想求 dp[i][j] 需要知道 dp[i+1][j-1]dp[i+1][j]dp[i][j-1] 这三个位置;再看看我们确定的 base case,填入 dp 数组之后是这样:

在这里插入图片描述
为了保证每次计算 dp[i][j]左下右方向的位置已经被计算出来,只能斜着遍历或者反着遍历:

在这里插入图片描述

public class LongestPalindromicSubsequence {

    public static void main(String[] args) {
        // 测试字符串
        String s = "bbabcbcab";
        // 调用方法找到最长回文子序列及其长度
        Result result = findLongestPalindromicSubsequence(s);
        // 输出结果
        System.out.println("最长回文子序列的长度是:" + result.length);
        System.out.println("最长回文子序列是:" + result.subsequence);
    }

    /**
     * 查找字符串s的最长回文子序列及其长度
     * @param s 给定的字符串
     * @return 包含最长回文子序列及其长度的Result对象
     */
    public static Result findLongestPalindromicSubsequence(String s) {
    	
        int n = s.length();
        if (n == 0) return new Result(0, "");

        //  将字符串转换为字符数组,可以避免多次调用 String.charAt 方法,从而提高性能
        char[] charArray = s.toCharArray();
        // dp数组,dp[i][j]表示字符串charArray[i...j]的最长回文子序列的长度
        int[][] dp = new int[n][n];

        // 初始化:每个单字符子串的回文长度为1
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }

        // 填充DP数组
        // len表示当前考虑的子串长度,从2开始,一直到字符串的总长度
        for (int len = 2; len <= n; len++) {
        	// i和j分别表示子串的起始和结束位置
            for (int i = 0; i < n - len + 1; i++) {
                int j = i + len - 1;
              
                if (charArray[i] == charArray[j]) {
                    // 如果两端字符相等,则最长回文子序列长度+2
                    // 表示去掉两端字符后的最长回文子序列长度加上这两个字符的长度。
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    // 否则,取去掉左端或右端字符后的较大值
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }

        // 回溯构建最长回文子序列:通过双指针和DP数组,回溯构建最长回文子序列。
        StringBuilder subsequence = new StringBuilder();
        // 使用双指针 i 和 j,从字符串的两端向中间移动。
        int i = 0, j = n - 1;
        while (i <= j) {
            if (charArray[i] == charArray[j]) {
                // 如果两端字符相等,加入到回文子序列中
                subsequence.append(charArray[i]);
                // 并同时移动 i 和 j
                i++;
                j--;
            } else if (dp[i + 1][j] > dp[i][j - 1]) {
                // 如果去掉左端字符后的子序列更长,向右移动
                i++;
            } else {
                // 否则,向左移动
                j--;
            }
        }

        // 构建完整的回文子序列:通过反转构建的回文子序列并拼接得到最终结果。

		// 将构建的回文子序列 subsequence 反转得到 reverseSubsequence
        StringBuilder reverseSubsequence = new StringBuilder(subsequence).reverse();
        if (subsequence.length() > 1) {
            // 如果回文子序列长度大于1,拼接中间部分,形成完整的回文子序列
            subsequence.append(reverseSubsequence.substring(1));
        } else {
            // 否则,直接拼接整个反转后的部分reverseSubsequence
            subsequence.append(reverseSubsequence);
        }

        // 返回结果对象,包含最长回文子序列长度及其内容
        return new Result(dp[0][n - 1], subsequence.toString());
    }

    // 内部类,保存最长回文子序列及其长度
    static class Result {
    	// 长度
        int length;
        // 最长回文子序列
        String subsequence;

        Result(int length, String subsequence) {
            this.length = length;
            this.subsequence = subsequence;
        }
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1958454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哈希表专题

题解之前&#xff1a; 1.有关unordered_map的count功能&#xff1a;查询key&#xff01; Leetcode 1.两数之和 解题思路&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> res;// key:具体的数值(便…

AI需求海量涌现,Scaleway如何用Spectrum-X 网络从容应对?

“没有好网络&#xff0c;别玩AIGC。” 如今&#xff0c;随着AI需求的大量涌现&#xff0c;越来越多用户意识到网络在AI集群中的重要性。一个超大规模、超高带宽、超强可靠的网络&#xff0c;可以为AI训练提供强有力支撑&#xff0c;从而节约训练成本、缩短训练时间&#xff0…

VBA快速对比数据行

实例需求&#xff1a;对于存在多行数据&#xff08;示例中为双行&#xff09;的项目&#xff0c;对比同一个项目的每列数据&#xff0c;高亮显示数据不同的单元格。 示例代码如下。 Function GetDiff(ByRef rng1 As Range, ByRef rng2 As Range) As RangeDim i As LongFor i …

dpdk发送udp报文

dpdk接收到udp报文后&#xff0c;自己构造一个udp报文&#xff0c;将收到的报文中的源mac&#xff0c;目的mac&#xff0c;源ip&#xff0c;目的ip&#xff0c;源端口和目的端口交换下顺序填充到新的udp报文中&#xff0c;报文中的负载数据和收到的udp保持一致。 注&#xff1…

CATIA V5R21安装包下载及图文安装教程

大家好&#xff0c;今天给大家分享下catia安装教程 注意安装前请退出杀毒软件&#xff0c;防止误报影响安装进程 下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;ypc6 01 在电脑D盘新建文件夹命名为CATIA,将下载的软件压缩包放置在该文件夹。 鼠标右击【C…

进行良好的文献综述能否提高学术研究的可信度

VersaBot一键生成文献综述 进行良好的文献综述 对于从多个方面提高学术研究的可信度至关重要&#xff1b; 1. 展示专业知识&#xff1a; 全面的回顾表明您对您所在领域的现有知识和相关理论有深入的了解。这将使您成为权威&#xff0c;并将您的研究置于更广泛的背景下。 2.…

初步入门C ++之类的概念

文章目录 0 Hello World!1 编译过程2 类2.1 类的概念2.2 构造函数与析构函数 0 Hello World! #include <iostream> //相当于#include <stdio.h>int main(int argc, char argv[]) {char c;std::cout << "Hello World!\n" <<…

入门 PyQt6 看过来(案例)14~ 分组

本文分享一个分组框功能&#xff0c;采用pyqt6里的QGroupBox​控件&#xff0c;效果如下&#xff1a;性别和专业分开为两个分组框内&#xff1a; ​ 1 功能实现思路 ui页面布局设计 性别和专业要设计成两个分组框&#xff1a; ​ 逻辑实现 引入信号和槽函数来实现点击单选…

Cybersecurity ASPICE实施策略-基于ISO/SAE 21434-亚远景科技

近几年&#xff0c;随着软件定义汽车和汽车的智能化和网联化&#xff0c;使得汽车融合了现代通信与网络通信技术&#xff0c;实现了车与人、车与车、车与道路、车与云端等智能信息交互和共享&#xff0c;也让车具备了环境感知、协同控制、智能决策等功能&#xff1b;与此同时&a…

构建可定制的表情选择器组件

你好呀&#xff0c;我是小邹。 概述 在当今的交互式Web应用中&#xff0c;表情符号&#xff08;Emoji&#xff09;已成为一种流行的沟通方式。为了提升用户体验并简化开发流程&#xff0c;本教程将引导您如何构建一个可高度定制的表情选择器组件。此组件将允许用户在Web表单中…

力扣621.任务调度器

力扣621.任务调度器 桶思想当桶放不满时 答案为桶面积 maxcount(最后一行) (max - 1)(n1)当桶放的满时 答案为任务总数 tasks.size()最终两者取大即可 class Solution {public:int leastInterval(vector<char>& tasks, int n) {int len tasks.size();vector<…

QT--聊天室

一、设计要求 用QT做一个聊天室&#xff0c; 制作一个服务器和客户端。可以进行注册、登录&#xff0c; 登陆成功后可以使用昵称进行发送、接收消息。 能根据昵称、聊天内容查询历史记录&#xff0c;也可以查询全部聊天记录。 。 二、客户端三级ui界面 三、项目代码 //在…

测试用例:确保软件质量的基石

大家好&#xff0c;我是一名测试开发工程师&#xff0c;已经开源一套【自动化测试框架】和【测试管理平台】&#xff0c;欢迎大家联系我&#xff0c;一起【分享测试知识&#xff0c;交流测试技术】 在当今这个数字化时代&#xff0c;软件已经成为人们日常生活、工作和学习中不可…

Hive3:Centos7环境部署Hive服务

一、安装说明 1、Hadoop集群情况 3台机器&#xff1a;4G2C、2G2C、2G2C 安装教程&#xff1a;Centos7环境安装Hadoop集群 2、安装MySQL&#xff0c;用于存储Hive的元数据 在102机器上安装MySQL 安装MySQL使用服务器的root账号 3、最后安装Hive 安装hive过程使用服务器的atgu…

fatal: Could not read from remote repository. 解决方法

问题描述&#xff1a; Git : fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists。 解决方法&#xff1a; 当在网上尝试大量方法仍然失败的时候&#xff0c;不妨试试这个方法。 在 github 上&…

ROUND() Function in SQL(四舍五入)

ROUND() Function in SQL ROUND() 函数用于将数值四舍五入到指定的小数位数或者整数位数。 不同的数据库系统可能会有一些细微的语法差异&#xff0c;但基本功能都是一致的。 1. 基本语法 ROUND(number, decimal_places)number: 要进行四舍五入的数值。decimal_places: 可选参…

2024年7月30日 十二生肖 今日运势

小运播报&#xff1a;2024年7月30日&#xff0c;星期二&#xff0c;农历六月廿五 &#xff08;甲辰年辛未月乙未日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;兔、马、猴 需要注意&#xff1a;狗、鼠、牛 喜神方位&#xff1a;西北方 财神方位&#xff1a;…

基于SpringBoot+Vue的游戏攻略分享平台(带1w+文档)

基于SpringBootVue的游戏攻略分享平台(带1w文档) 本系统为了数据库结构的灵活性所以打算采用MySQL来设计数据库&#xff0c;而java技术&#xff0c;B/S架构则保证了较高的平台适应性。本文主要介绍了本系统的开发背景&#xff0c;所要完成的功能和开发的过程&#xff0c;主要说…

大数据-54 Kafka 安装配置 环境变量配置 启动服务 Ubuntu配置 ZooKeeper

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

零基础入门转录组数据分析——加权基因共表达网络分析(WGCNA,Weighted correlation network analysis)

零基础入门转录组数据分析——加权基因共表达网络分析&#xff08;WGCNA&#xff0c;Weighted correlation network analysis&#xff09; 目录 零基础入门转录组数据分析——加权基因共表达网络分析&#xff08;WGCNA&#xff0c;Weighted correlation network analysis&#…