文章目录
零、题目描述
题目链接:力扣 14. 最长公共前缀
题目描述:

示例 1:
输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
示例 2:
输入:strs = [“dog”,“racecar”,“car”]
输出:“”
解释:输入不存在公共前缀。
提示:
1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 如果非空,则仅由小写英文字母组成
一、为什么这道题值得你花几分钟的时间看完?
这道题是字符串处理的经典入门题,更是面试中“考察基础编程能力”的高频题——它看似简单,却能全方位检验你的“模拟思维”“边界处理”和“代码优化意识”,是夯实字符串操作基础的绝佳案例。
题目核心价值
- 模拟思维的“入门钥匙”:题目逻辑直观,无需复杂算法,却能有效训练“将自然语言描述转化为代码逻辑”的能力,是新手入门字符串题型的最佳起点。
- 边界场景的“试金石”:空字符串、单元素数组、字符串长度不一致、无公共前缀等特殊情况,能充分检验代码的稳健性,避免“看似能过样例,实则漏洞百出”。
- 多解法的“练兵场”:横向遍历、纵向遍历、排序法等多种思路均可解题,能让你对比不同实现的优劣,培养“一题多解”的思维习惯。
- 工程化思维的“缩影”:类似“公共前缀查找”的场景在工作中高频出现(如文件路径匹配、接口参数校验、字典树构建),解题思路可直接迁移复用。
- 面试的“基础门槛”:作为字符串题型的入门题,常出现在笔试第一题或面试热身环节,快速写出简洁、高效、无bug的代码,能给面试官留下“基础扎实”的良好印象。
面试考察的核心方向
- 模拟逻辑的清晰度:能否将“找公共前缀”的过程拆分为可执行的代码步骤,避免逻辑混乱。
- 边界条件的考虑:是否能覆盖所有特殊用例,体现代码的鲁棒性。
- 代码的简洁性与效率:能否用简洁的语法实现核心逻辑,同时关注时间/空间复杂度的优化。
- 字符串操作的熟练度:对字符串的截取、比较、长度获取等基础接口的使用是否熟练。
- 算法思路的拓展性:能否在基础解法上,提出更优的实现(如利用排序简化对比),体现思维的深度。
掌握这道题,既能夯实字符串操作的基础,又能培养“模拟思维”和“边界处理意识”,后续遇到更复杂的字符串问题(如子串匹配、字符串转换)时,能更从容地应对。
二、算法原理
最长公共前缀的核心定义是:所有字符串共有的、从第一个字符开始的连续子串。如果存在任意一个字符串不包含该子串,或子串长度超过某个字符串的长度,则该子串不是公共前缀。
解题的关键突破口是:通过“逐步缩小公共前缀范围”或“逐位验证公共字符”的方式,找到所有字符串的交集。以下是两种最经典、最易实现的算法思路:
1. 横向遍历(两两对比法)
核心思路:
将“多个字符串找公共前缀”转化为“两两字符串找公共前缀”的迭代过程。以第一个字符串为初始公共前缀,依次与后续字符串对比,更新公共前缀为两者的最长公共部分,直到遍历完所有字符串或公共前缀为空(提前终止),如下图👇:

步骤拆解
- 边界处理:若字符串数组为空,直接返回空字符串(你的代码默认数组非空,可补充优化);
- 初始化公共前缀:将第一个字符串作为初始前缀
ret; - 迭代更新前缀:遍历数组中剩余的每个字符串
strs[i],调用findCommon函数计算ret与strs[i]的公共前缀,并更新ret; - 返回最终的
ret。
纵向遍历(逐位验证法)
核心思路:
先确定所有字符串的最短长度(公共前缀长度不可能超过最短字符串),再逐位验证所有字符串的对应位置字符是否相同。若某一位所有字符串都相同,则加入结果;若存在不同,则立即终止验证。
步骤拆解:
- 边界处理:若字符串数组为空,直接返回空字符串;
- 计算最短字符串长度
size(公共前缀的最大可能长度); - 逐位验证:遍历每个字符位置
j(从0到size-1):- 验证所有字符串的第
j位是否相同(通过i遍历所有字符串对比); - 若所有字符串第
j位相同,将该字符加入结果ret; - 若存在不同,立即终止遍历;
- 验证所有字符串的第
- 返回
ret。

大体意思是根据这两个算法思路独立去写代码,提升代码能力,并且这道题在模拟的写法上有很多种,只要能跑过就完美。
三、代码实现
横向遍历(两两对比法)
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
// 边界处理:数组为空时返回空字符串
if (strs.empty()) return "";
string ret = strs[0]; // 以第一个字符串为初始公共前缀
// 遍历后续所有字符串,迭代更新公共前缀
for (int i = 1; i < strs.size(); i++) {
ret = findCommon(ret, strs[i]);
// 提前终止:若公共前缀为空,无需继续遍历
if (ret.empty()) break;
}
return ret;
}
// 辅助函数:计算两个字符串的最长公共前缀
string findCommon(string& s1, string& s2) {
int i = 0;
// 遍历到较短字符串的末尾,且字符相同则继续
while (i < min(s1.size(), s2.size()) && s1[i] == s2[i]) {
i++;
}
// 截取前i个字符作为公共前缀(i=0时返回空字符串)
return s1.substr(0, i);
}
};
代码细节与易错点:
- 边界处理:要验证数组为空的判断,避免
strs[0]越界。 - 提前终止:当
ret为空时,直接跳出循环,减少无效计算。 - 辅助函数解耦:将“两两对比”逻辑抽离为独立函数,代码结构更清晰,可复用。
min函数使用:需包含<algorithm>头文件,否则会编译报错。substr用法:s1.substr(0, i)表示从索引0开始截取i个字符,i=0时返回空字符串,无需额外处理。
2. 纵向遍历(逐位验证法)
#include <vector>
#include <string>
#include <climits> // 用于 INT_MAX
#include <algorithm>
using namespace std;
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
// 边界处理:数组为空时返回空字符串
if (strs.empty()) return "";
int size = INT_MAX;
// 计算所有字符串的最短长度(公共前缀最大可能长度)
for (int i = 0; i < strs.size(); i++) {
size = min(size, (int)strs[i].size());
}
string ret = "";
// 逐位验证每个字符位置
for (int j = 0; j < size; j++) {
int i = 0;
// 验证所有字符串的第j位是否相同
while (i < strs.size() - 1) {
if (strs[i][j] != strs[i+1][j]) {
break; // 有不同字符,终止当前位验证
}
i++;
}
// 若i遍历到最后一个字符串,说明当前位所有字符相同
if (i == strs.size() - 1) {
ret.push_back(strs[i][j]);
} else {
break; // 存在不同字符,终止所有验证
}
}
return ret;
}
};
代码细节与易错点
- 边界处理:要判断数组为空的判断,避免后续循环逻辑出错;
- 最短长度计算:
strs[i].size()返回size_t类型,需强制转换为int避免类型不匹配; - 循环终止条件:
i < strs.size() - 1确保对比到最后一个字符串(通过i从0到n-2,对比i和i+1); - 提前终止:一旦某一位存在不同字符,立即跳出所有循环,减少冗余计算;
- 字符拼接:使用
ret.push_back()高效添加字符,比ret += strs[i][j]性能更优。
3. 复杂度分析
| 算法 | 时间复杂度 | 空间复杂度 | 核心优势 |
|---|---|---|---|
| 横向遍历 | O(n * k) | O(1) | 逻辑清晰,代码解耦,易维护 |
| 纵向遍历 | O(n * k) | O(1) | 提前终止场景更多,平均效率更高 |
n 为字符串数组的长度,k 为所有字符串的平均长度(或最短字符串的长度);
四、总结
核心考点回顾
- 模拟思维:将“找公共前缀”的自然逻辑,转化为“两两对比”或“逐位验证”的代码步骤,体现逻辑拆解能力;
- 边界处理:覆盖空数组、空字符串、字符串长度不一致等特殊情况,是代码鲁棒性的关键;
- 代码结构优化:横向遍历通过辅助函数解耦逻辑,纵向遍历通过最短长度限制循环范围,均体现了代码设计能力;
- 字符串操作:熟练使用
substr、size()、push_back()等基础接口,简化代码实现; - 效率优化:通过提前终止遍历,减少无效计算,提升代码执行效率。
解题思路迁移
- 公共子串/子序列问题:类似“找公共部分”的逻辑,可迁移到“最长公共子序列”“公共后缀查找”等问题;
- 逐位验证思想:在“字符匹配”“格式校验”等场景中(如验证所有字符串是否以某个前缀开头),可复用逐位对比的逻辑;
- 辅助函数解耦:将重复逻辑抽离为独立函数,是工程化开发中提升代码可读性和复用性的常用技巧。
常见错误总结
- 忽略空数组边界条件,导致
strs[0]越界; - 横向遍历未提前终止,当公共前缀为空时仍继续遍历,浪费性能;
- 纵向遍历中未计算最短长度,导致访问短字符串的越界索引;
- 类型不匹配:
size_t与int混用,导致编译报错或逻辑错误。
五、下题预告
下一篇我们将攻克字符串题型中的经典难题——力扣 5. 最长回文子串!这道题是面试中的“高频重难点”,不仅考察字符串的遍历与匹配,更需要掌握“中心扩展法”“动态规划”等核心解题技巧,同时还要兼顾时间复杂度的优化。
无论是笔试中的算法题,还是面试中的思路阐述,这道题都能充分检验你的“逻辑推理能力”和“优化意识”。相信掌握了这道题,你对字符串问题的理解会再上一个台阶!
Doro 带着小花🌸来啦!🌸奖励🌸坚持啃完基础题的你!基础扎实才能走得更远,下一道题虽然有难度,但只要跟着思路一步步拆解,一定能攻克它~ 别忘了收藏本文,后续刷题时随时回顾知识点,也欢迎在评论区分享你的解题感悟,我们下道题不见不散!

3819

被折叠的 条评论
为什么被折叠?



