欢迎光临
我们一直在努力

字符串核心(基础操作 + 回文)

一、前言

字符串是编程中最常用的数据类型之一,而反转、子串截取、字符计数、回文判断是字符串的核心基础操作,也是面试高频考点。本文将用 3 小时精准拆解这些知识点,结合 3 道 LeetCode 经典题目(Easy+Easy+Medium),从理论到实战帮你彻底掌握,适合入门进阶和面试复盘。

二、0-30 分钟:字符串核心知识点精讲

2.1 字符串本质与存储特性

  • 字符串是字符的有序序列,底层在 Java 中以char[]数组实现(不可变特性:String 类被 final 修饰,修改时会创建新对象);
  • 关键特性:有序性(支持索引访问)、不可变性(需注意性能开销)、可比较性(equals ()/compareTo ())。

2.2 三大基础操作

2.2.1 字符串反转
  • 核心思路:
  • 双指针法(原地修改,适合字符数组):左右指针分别从首尾向中间移动,交换元素;
  • 辅助容器法(适合不可变字符串):遍历原字符串,从后向前存入新字符串 / StringBuilder。
  • 时间复杂度:O (n)(需遍历所有字符),空间复杂度:O (1)(双指针原地)/ O (n)(辅助容器)。
2.2.2 子串截取
  • Java 关键 API:String substring(int beginIndex)(从 beginIndex 截取到末尾)、String substring(int beginIndex, int endIndex)(左闭右开,[begin, end));
  • 注意事项:索引越界会抛出StringIndexOutOfBoundsException,endIndex 超出字符串长度时默认截取到末尾。
2.2.3 字符计数
  • 核心思路:
  • 数组统计(适合 ASCII 字符):用大小为 256 的 int 数组记录每个字符的出现次数;
  • 哈希表统计(适合 Unicode 字符):用HashMap<Character, Integer>存储字符与计数的映射;
  • 字符串 API 辅助:String.chars()流式统计(Java 8+)。

2.3 回文判断核心逻辑

  • 回文定义:正读和反读完全相同的字符串(如 "abcba"、"A man, a plan, a canal: Panama");
  • 核心判断思路:
  • 预处理:过滤非字母数字字符(保留 a-z、A-Z、0-9),统一大小写(避免大小写干扰);
  • 验证:双指针从首尾向中间对比,所有字符一致则为回文。
  • 延伸:回文子串 / 子序列问题(需关注 “连续” 与 “非连续” 的区别)。

三、30-110 分钟:刷题实战(3 道经典题)

3.1 Easy:LeetCode344 反转字符串

题目描述

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O (1) 的额外空间解决这一问题。

解题思路
  • 核心:利用字符串的有序性,双指针原地交换;
  • 步骤:
  • 定义左指针 left = 0,右指针 right = s.length – 1;
  • 循环条件:left < right;
  • 交换 s[left] 和 s[right],然后 left++、right–,直到指针相遇。
Java 代码(高亮版)

java

运行

class Solution {
public void reverseString(char[] s) {
// 双指针初始化
int left = 0;
int right = s.length – 1;
// 循环交换,直到指针相遇
while (left < right) {
// 临时变量保存左指针字符
char temp = s[left];
s[left] = s[right];
s[right] = temp;
// 指针移动
left++;
right–;
}
}
}

复杂度分析
  • 时间复杂度:O (n),n 为字符数组长度,需遍历一半字符(O (n/2) = O (n));
  • 空间复杂度:O (1),仅使用常数级额外空间(临时变量 temp),满足原地修改要求。
注意事项
  • 边界处理:当数组为空(length=0)或长度为 1 时,无需交换,直接返回;
  • 无需额外数组:题目禁止分配新数组,双指针是最优解法;
  • 字符数组特性:Java 中 char [] 是可变的,可直接通过索引修改元素。

3.2 Easy:LeetCode125 验证回文串

题目描述

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样,则可以认为该短语是一个回文串。字母和数字都属于字母数字字符。给你一个字符串 s,请你验证它是否是回文串。

解题思路
  • 核心:先预处理字符串(过滤 + 大小写转换),再用双指针验证回文;
  • 步骤:
  • 预处理:遍历字符串,保留字母数字字符,统一转为小写;
  • 双指针验证:左指针从 0 开始,右指针从预处理后字符串末尾开始,逐一对比字符是否一致;
  • 若所有对比都一致则为回文,否则不是。
Java 代码(高亮版)

java

运行

class Solution {
public boolean isPalindrome(String s) {
// 步骤1:预处理字符串(过滤非字母数字 + 转小写)
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
//toCharArray() 是 Java 中 String 类的内置方法,核心作用是:将当前字符串对
象,转换为一个对应的 char 类型数组
// 判断是否为字母或数字
if (Character.isLetterOrDigit(c)) {
// 转为小写并加入StringBuilder
sb.append(Character.toLowerCase(c));
}
}
// 预处理后的字符串
String processed = sb.toString();
//将可变的 StringBuilder 对象中存储的字符序列,转换为一个标准的、
不可变的 String 字符串对象
// 步骤2:双指针验证回文
int left = 0;
int right = processed.length() – 1;
while (left < right) {
// 对比左右指针字符
if (processed.charAt(left) != processed.charAt(right)) {
return false;
}
left++;
right–;
}
return true;
}
}

优化版代码(无额外 StringBuilder,双指针直接处理原字符串)

java

运行

class Solution {
public boolean isPalindrome(String s) {
int left = 0;
int right = s.length() – 1;
while (left < right) {
// 左指针跳过非字母数字字符
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
left++;
}
// 右指针跳过非字母数字字符
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
right–;
}
// 对比(转小写后)
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
left++;
right–;
}
return true;
}
}

复杂度分析
  • 原始版:时间复杂度 O (n)(遍历 2 次字符串:预处理 + 验证),空间复杂度 O (n)(StringBuilder 存储预处理结果);
  • 优化版:时间复杂度 O (n)(仅遍历 1 次字符串),空间复杂度 O (1)(无额外容器),更优。
注意事项
  • 非字母数字字符:包括空格、标点、符号等,需完全过滤;
  • 大小写无关:如 "A" 和 "a" 视为相同,必须统一转换;
  • 空字符串 / 全非字母数字:预处理后为空,视为回文(返回 true)。

3.3 Medium:LeetCode5 最长回文子串

题目描述

给你一个字符串 s,找到 s 中最长的回文子串。如果字符串的长度为 1,则返回该字符串。

解题思路
  • 核心:回文子串的对称性 → 中心扩展法(入门必学,时间复杂度 O (n²),空间复杂度 O (1),适合入门);
  • 关键观察:
  • 奇数长度回文:中心是 1 个字符(如 "abcba" 的中心是 "c");
  • 偶数长度回文:中心是 2 个字符(如 "abba" 的中心是 "bb");
  • 步骤:
  • 遍历字符串每个字符(作为奇数中心)和每两个相邻字符(作为偶数中心);
  • 对每个中心,向左右扩展,记录最大回文子串的起始和结束索引;
  • 遍历结束后,截取最长回文子串返回。
Java 代码(高亮版)

java

运行

class Solution {
// 记录最长回文子串的起始索引和长度(避免每次截取字符串,提升效率)
private int start = 0;
private int maxLen = 1;

public String longestPalindrome(String s) {
int n = s.length();
// 边界条件:字符串长度<=1,直接返回
if (n <= 1) {
return s;
}
// 遍历每个可能的中心,扩展回文
for (int i = 0; i < n; i++) {
expandAroundCenter(s, i, i); // 奇数长度回文(中心1个字符)
expandAroundCenter(s, i, i+1); // 偶数长度回文(中心2个字符)
}
// 截取最长回文子串(start到start+maxLen)
return s.substring(start, start + maxLen);
}

// 中心扩展核心方法:left和right为初始中心
private void expandAroundCenter(String s, int left, int right) {
int n = s.length();
// 向左右扩展,直到字符不相等或越界
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
left–;
right++;
}
// 计算当前回文子串的长度(right – left – 1,因为退出循环时left和right已越界/不相等)
int currentLen = right – left – 1;
// 更新最长回文子串的起始索引和长度
if (currentLen > maxLen) {
maxLen = currentLen;
// 起始索引:left+1(因为退出循环时left多减了1)
start = left + 1;
}
}
}

复杂度分析
  • 时间复杂度:O (n²),n 为字符串长度。遍历每个中心(O (n) 个中心),每个中心最多扩展 O (n) 次,总次数 O (n²);
  • 空间复杂度:O (1),仅使用常数级额外变量(start、maxLen、left、right),无额外容器。
注意事项
  • 中心扩展的边界:left >= 0(左边界)、right < n(右边界),避免索引越界;
  • 回文长度计算:退出循环时,left 和 right 已超出有效回文范围,实际长度为 right – left – 1;
  • 起始索引更新:start = left + 1(因为 left 多减了 1),避免截取时出错;
  • 其他解法:Manacher 算法(时间复杂度 O (n),进阶用),但中心扩展法更易理解和实现,适合面试入门。
  • class Solution {
    public String longestPalindrome(String s) {
    if (s == null || s.length() == 0) return "";

    // 1. 预处理字符串,统一成奇数长度
    StringBuilder sb = new StringBuilder();
    sb.append("^");
    for (char c : s.toCharArray()) {
    sb.append("#").append(c);
    }
    sb.append("#").append("$");
    String T = sb.toString();

    int n = T.length();
    int[] p = new int[n]; // 回文半径数组
    int C = 0, R = 0; // 中心、最右边界

    // 记录最长回文的中心和半径
    int maxCenter = 0, maxRadius = 0;

    // 2. 遍历处理
    for (int i = 1; i < n – 1; i++) {
    // 利用对称性初始化 p[i]
    int mirror = 2 * C – i;
    if (i < R) {
    p[i] = Math.min(R – i, p[mirror]);
    }

    // 3. 往外扩展
    while (T.charAt(i + p[i] + 1) == T.charAt(i – p[i] – 1)) {
    p[i]++;
    }

    // 4. 若超过 R,更新 C 和 R
    if (i + p[i] > R) {
    C = i;
    R = i + p[i];
    }

    // 记录最大值
    if (p[i] > maxRadius) {
    maxRadius = p[i];
    maxCenter = i;
    }
    }

    // 5. 还原回原字符串
    int start = (maxCenter – maxRadius) / 2;
    return s.substring(start, start + maxRadius);
    }
    }

四、总结与复盘

4.1 核心知识点回顾

  • 字符串基础操作:反转(双指针最优)、子串截取(注意左闭右开)、字符计数(数组 / 哈希表);
  • 回文问题:预处理(过滤 + 大小写)+ 双指针验证,回文子串用中心扩展法(覆盖奇偶情况)。
  • 4.2 解题技巧提炼

    • 双指针:字符串反转、回文验证的万能工具,优先考虑(空间效率高);
    • 中心扩展:解决回文子串问题的入门最优解,需兼顾奇偶中心;
    • 预处理:回文问题必做步骤,避免非目标字符干扰。

    4.3 延伸学习建议

  • 进阶题目:LeetCode647(回文子串计数)、LeetCode516(最长回文子序列);
  • 优化算法:Manacher 算法(线性时间解决最长回文子串);
  • 实战场景:字符串匹配(KMP 算法)、正则表达式(辅助字符串处理)。
  • 赞(0)
    未经允许不得转载:171主机测评 » 字符串核心(基础操作 + 回文)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址