当前位置: 首页 > news >正文

LeetCode 214:最短回文串

LeetCode 214:最短回文串

在这里插入图片描述

问题定义与核心挑战

给定字符串 s,需通过在前面添加字符将其转换为回文串,求最短的 such 回文串。例如:

  • 输入 s = "abcd" → 输出 dcbabcd(添加 dcb 到前面)。
  • 核心挑战:如何高效找到 最长回文前缀(从开头开始的最长回文子串),从而最小化添加的字符数。

核心思路:KMP 的 LPS 数组

利用 KMP 算法的最长公共前后缀(LPS)数组,将问题转换为寻找字符串的对称结构:

  1. 构造辅助串t = s + "#" + reverse(s)# 避免前缀和后缀过度重叠)。
  2. 计算 LPS 数组:LPS 数组的最后一个元素值,即为 s最长回文前缀长度
  3. 构造结果:将 s 中最长回文前缀之后的部分反转,添加到原字符串前。

算法步骤详解

步骤 1:反转字符串,构造辅助串 t
  • 反转 s 得到 rev_s,构造 t = s + "#" + rev_s
  • 作用:通过 t 的 LPS 数组,找到 s 的前缀与 rev_s 的后缀的最长匹配(该匹配对应 s 的最长回文前缀)。
String rev_s = new StringBuilder(s).reverse().toString();
String t = s + "#" + rev_s;
步骤 2:计算 LPS 数组(KMP 核心)

LPS 数组定义:lps[i] 表示 t[0..i]最长公共前后缀长度(前缀和后缀相同的最长子串长度)。

计算逻辑

  • 初始化 len = 0(当前最长公共前后缀长度),lps[0] = 0
  • 遍历 t(从 i=1 开始):
    • t[i] == t[len],则 len++lps[i] = leni++
    • 若不匹配,若 len > 0,则 len = lps[len-1](回退到之前的有效长度);否则 lps[i] = 0i++
int[] lps = new int[t.length()];
int len = 0; // 当前最长公共前后缀长度
for (int i = 1; i < t.length(); ) {if (t.charAt(i) == t.charAt(len)) {len++;lps[i] = len;i++;} else {if (len > 0) {len = lps[len - 1]; // 回退} else {lps[i] = 0;i++;}}
}
步骤 3:构造最短回文串
  • 最长回文前缀长度为 lps[t.length()-1](LPS 数组最后一个元素)。
  • 截取 s最长回文前缀之后的部分s.substring(max_len)),反转后添加到原字符串前。
int max_len = lps[t.length() - 1];
String add = new StringBuilder(s.substring(max_len)).reverse().toString();
return add + s;

关键逻辑解析

1. 辅助串 t 的作用
  • t = s + "#" + rev_s 确保 s 的前缀与 rev_s 的后缀匹配时,不会跨 srev_s 的边界(如 s=aaaarev_s=aaaa,不加 # 会导致匹配长度为 8,而实际最长回文前缀是 4)。
2. LPS 数组的意义
  • lps[t.length()-1] 表示 s 的前缀与 rev_s 的后缀的最长匹配长度,该长度对应 s最长回文前缀长度(因为 rev_ss 的反转,匹配的前缀必然是回文)。
3. 时间复杂度
  • 构造 tO(n)ns 的长度)。
  • 计算 LPS 数组:O(n)(每个字符最多入队、出队一次)。
  • 反转和拼接:O(n)
  • 整体复杂度:O(n),高效处理大输入(如 n=5×10⁴)。

完整代码(Java)

public class Solution {public String shortestPalindrome(String s) {// 处理空字符串if (s == null || s.isEmpty()) {return "";}// 步骤1:反转字符串,构造辅助串 t = s + "#" + rev_sString rev_s = new StringBuilder(s).reverse().toString();String t = s + "#" + rev_s;// 步骤2:计算 LPS 数组int[] lps = new int[t.length()];int len = 0; // 当前最长公共前后缀的长度for (int i = 1; i < t.length(); ) {if (t.charAt(i) == t.charAt(len)) {len++;lps[i] = len;i++;} else {if (len > 0) {// 回退到前一个可能的长度len = lps[len - 1];} else {lps[i] = 0;i++;}}}// 步骤3:构造最短回文串int max_len = lps[t.length() - 1];String add = new StringBuilder(s.substring(max_len)).reverse().toString();return add + s;}
}

示例验证(以示例 2 为例)

输入s = "abcd"

  1. 反转与构造 trev_s = "dcba"t = "abcd#dcba"
  2. 计算 LPS 数组:最后一个元素 lps[8] = 1(最长匹配长度为 1,即 s 的最长回文前缀是 "a")。
  3. 构造结果s.substring(1) = "bcd",反转后为 "dcb",最终结果 dcb + abcd = "dcbabcd",与示例一致。

该方法通过 KMP 思想 高效定位最长回文前缀,将时间复杂度优化到 O(n),是处理“最短回文串”问题的经典方案。

http://www.dtcms.com/a/303017.html

相关文章:

  • Leetcode148. 排序链表 中遇到的错误
  • 【LeetCode 热题 100】(一)哈希
  • 设计模式(十七)行为型:迭代器模式详解
  • c/c++ 函数返回指针和引用所引发的问题
  • Linux系统Centos7 安装mysql5.7教程 和mysql的简单指令
  • JVM 内存模型深度解析:原子性、可见性与有序性的实现
  • FFmpeg 安装与使用
  • 从JPEG到SER:小波+CNN如何横扫CVPR/ICASSP?
  • C#_索引器
  • 最新!Polkadot 更新 2025 路线图
  • 【C++】priority_queue的模拟实现
  • Tchebycheff变换简介
  • 应急响应案例处置(下)
  • Dify-14: 工作流API端点
  • gRPC 为 Sui 上更智能的数据访问奠定基础
  • 【Kubernetes】使用StatefulSet进行的资源调度,删除更新策略
  • Linux 应用程序组成
  • haproxy原理及实验演示(实现服务器集群的负载均衡)
  • 火线、零线、地线
  • 雷达系统设计学习:自制6GHz FMCW Radar
  • C++中std::variant的使用详解和实战代码示例
  • 三角洲摸金模拟器(简易版本)(开源)
  • 黑马JavaWeb【复习到哪更新到哪】
  • Coze Studio概览(二)
  • 【MySQL基础篇】:MySQL常用数据类型的选择逻辑与正确使用
  • Go语言-->变量
  • 【Practical Business English Oral Scene Interpretation】在职日常交流No.1~6
  • MySQL面试题及详细答案 155道(001-020)
  • 重构企业交互逻辑:云蝠智能 Voice Agent 的落地价值与实践指南
  • 设计模式(二十一)行为型:状态模式详解