🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
摘要:面试中字符串算法是高频考点,本文从最基础的字符串反转出发,逐步深入到回文字符串判断,再到经典的回文变种问题。每道题都提供多种解法,带你彻底搞懂字符串算法的核心套路!
📌 前言
最近在准备面试,发现字符串相关的算法题出现频率极高。尤其是反转字符串 、回文判断 、回文变种这三类题目,几乎成了大厂面试的"标配"。
本文将这三道经典题目串联起来,从最简单的反转开始,一步步升级难度,帮你建立起字符串算法的完整知识体系。每道题都提供 API 解法 和 双指针解法,让你在面试中能灵活应对。
🎯 本文适合谁
- 正在准备前端/后端面试的同学
- 想要巩固字符串算法基础的开发者
- 对 JavaScript 底层机制感兴趣的同学
📚 第一题:反转字符串
题目描述
给定一个字符串,将其反转。例如:"abc" → "cba"
💡 核心知识点:JS 中字符串是简单数据类型
在 JavaScript 中,字符串是简单数据类型 ,并没有提供 reverse 方法。但是数组有!
javascript
console.log([1, 2, 3].reverse()); // [3, 2, 1]
那字符串怎么反转呢?思路很简单:先拆成数组,反转数组,再拼回字符串。
解法:split → reverse → join
javascript
const str = 'abc';
// 1. split('') 将字符串拆分成字符数组
const arr = str.split(''); // ['a', 'b', 'c']
// 2. reverse() 反转数组
arr.reverse(); // ['c', 'b', 'a']
// 3. join('') 将数组拼回字符串
const result = arr.join(''); // 'cba'
console.log(result); // 'cba'
一行搞定:
javascript
const reverseStr = (str) => str.split('').reverse().join('');
🤔 延伸思考:为什么字符串能调用 .length?
你可能会好奇:字符串是简单数据类型,为什么 'abc'.length 能正常工作?
这就是 JavaScript 的**包装类(Wrapper Class)**机制:
javascript
let str = 'abc'; // 简单数据类型,存在栈内存
str.length; // ??简单类型怎么有属性?
// JS 底层偷偷帮你做了一件事:
// new String(str) → 包装成 String 实例(对象,存在堆内存)
// 用完后自动销毁,把 str 改回简单数据类型
这就像 JS 在底层帮你"摇人"------临时把简单类型包装成对象,用完再还原。
🤔 延伸思考:Object.prototype.toString.call() 是什么?
面试常问:如何精确判断一个变量的类型?
javascript
Object.prototype.toString.call('abc'); // '[object String]'
Object.prototype.toString.call([1, 2, 3]); // '[object Array]'
Object.prototype.toString.call({a: 1}); // '[object Object]'
核心原理:
toString是 Object 原型上的方法,作用是把对象序列化(字符串化)call是函数借用------让toString方法中的this指向你传入的对象- 不同子类重写了
toString,所以能精确区分类型
javascript
// call 的本质:借用函数,改变 this 指向
let o = { name: '张三', say() { console.log(this.name); } };
let obj = { name: '李四' };
o.say(); // '张三' ------ this 指向 o
o.say.call(obj); // '李四' ------ this 指向 obj,函数借用!
📚 第二题:判断回文字符串
题目描述
给定一个字符串,判断它是否是回文字符串(正着读和倒着读一样)。例如:"yessey" 是回文,"hello" 不是。
解法一:API 解法(面试官可能会让你换个思路)
javascript
function isPalindrome(str) {
return str === str.split('').reverse().join('');
}
console.log(isPalindrome('yessey')); // true
console.log(isPalindrome('hello')); // false
优点 :简洁直观 缺点:需要额外的空间创建数组,面试官通常会追问"能不能不用额外空间?"
解法二:双指针解法(面试加分项 ✅)
回文的核心特性是对称性------从两端向中间逼近,每一对字符都应该相等。
javascript
function isPalindrome(str) {
const len = str.length;
// 双指针:左指针从头开始,右指针从尾开始
for (let i = 0; i < len / 2; i++) {
// 如果对应位置的字符不相等,一定不是回文
if (str[i] !== str[len - 1 - i]) {
return false;
}
}
return true;
}
console.log(isPalindrome('yessey')); // true
console.log(isPalindrome('hello')); // false
思路图解:
ini
y e s s e y
↑ ↑ y === y ✅
↑ ↑ e === e ✅
↑ ↑ s === s ✅
所有对应字符都相等 → 是回文!
两种解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 面试评价 |
|---|---|---|---|
| API 解法 | O(n) | O(n) | 能用,但不够优 |
| 双指针 | O(n) | O(1) | ⭐ 面试加分项 |
📚 第三题:回文变种------最多删除一个字符
题目描述
给定一个非空字符串
s,最多删除一个字符,判断是否能成为回文字符串。
例如:
"aba"→ 已经是回文,返回true"abca"→ 删除'c'后变成"aba",返回true"abc"→ 无论删哪个都不是回文,返回false
这道题是回文判断的进阶版,在大厂面试中出现频率很高!
解题思路
核心思想:利用回文的对称性 + 双指针。
- 用双指针从两端向中间扫描
- 当遇到不匹配的字符时,有两种选择:
- 删除左边的字符 → 检查
[i+1, j]是否是回文 - 删除右边的字符 → 检查
[i, j-1]是否是回文
- 删除左边的字符 → 检查
- 只要其中一种情况是回文,就返回
true
完整代码
javascript
function validPalindrome(s) {
const len = s.length;
let i = 0;
let j = len - 1;
// 双指针从两端向中间逼近
while (i < j && s[i] === s[j]) {
i++;
j--;
}
// 如果已经扫描完,说明本身就是回文
// 如果遇到不匹配,尝试删除左边或右边的字符
if (isPalindrome(i + 1, j) || isPalindrome(i, j - 1)) {
return true;
}
// 辅助函数:判断子串是否是回文
function isPalindrome(st, ed) {
while (st < ed) {
if (s[st] !== s[ed]) {
return false;
}
st++;
ed--;
}
return true;
}
return false;
}
// 测试
console.log(validPalindrome('abaca')); // true → 删除 'c' 得到 'aba'
console.log(validPalindrome('aba')); // true → 本身就是回文
console.log(validPalindrome('abc')); // false → 删哪个都不行
图解执行过程
以 "abaca" 为例:
css
第一轮:双指针扫描
a b a c a
↑ ↑ a === a ✅
↑ ↑ b !== c ❌ → 遇到冲突!
此时有两个选择:
选择1:跳过左边 'b',检查 "aca" → 是回文 ✅
选择2:跳过右边 'c',检查 "aba" → 是回文 ✅
只要有一个成立,返回 true!
复杂度分析
| 复杂度 | 值 | 说明 |
|---|---|---|
| 时间 | O(n) | 最多扫描两遍字符串 |
| 空间 | O(1) | 只用了几个指针变量 |
💡 核心总结
知识点串联
perl
反转字符串 → 理解 split/reverse/join
↓
判断回文字符串 → 双指针的对称性思想
↓
回文变种(删一个字符)→ 双指针 + 分情况讨论
面试要点速记
| 考点 | 关键词 | 面试话术 |
|---|---|---|
| 反转字符串 | split + reverse + join | "字符串没有 reverse,先拆成数组" |
| 包装类 | Wrapper Class | "JS 临时包装简单类型为对象,用完即销毁" |
| call/apply/bind | 函数借用 | "借用别人的方法,改变 this 指向" |
| 回文判断 | 双指针、对称性 | "从两端向中间逼近,对应字符比较" |
| 回文变种 | 分情况讨论 | "遇到冲突时,尝试跳过左边或右边" |
通用解题套路
- 字符串操作类:先想能不能转数组处理(split → 操作 → join)
- 对称性问题 :优先考虑双指针,从两端向中间逼近
- 变种问题 :在基础解法上加分支讨论,用辅助函数复用逻辑
🔗 参考资料
- MDN - String
- MDN - Function.prototype.call()
- LeetCode 125 - Valid Palindrome
- LeetCode 680 - Valid Palindrome II
💬 交流讨论
你在面试中遇到过哪些字符串相关的算法题?欢迎在评论区分享你的解题思路!
如果觉得这篇文章对你有帮助,点个赞👍 收藏⭐ 关注👆,后续会更新更多面试算法题解系列!
觉得有用?点个赞👍收藏⭐关注👆,下次更新更多前端算法面试玩法!