LeetCode 14简单字符串 · 扫描
最长公共前缀 图解题解
把所有词竖着摞、逐列扫,一有不同立刻停,O(S) 拿到最长公共前缀。
把所有单词竖着摞成一列,逐列往右看:只要这一列每个词的同位字母和第一个词的一样,就算进公共前缀;一旦有词短了、或某个字母对不上,立刻停——摞着比比列,比两两再取交集清爽得多。
这道题到底在问什么
求字符串数组中所有字符串的最长公共前缀;若不存在公共前缀,返回空串。
- 输入
- strs=["interpreter", "interpreting", "interpreted", "interpretation"]
- 输出
- "interpret"
最优解:一步一步想明白
- 3记住这条:逐列比较所有字符串的同一位,全相同就延长,一旦某个不同或某串到头,前缀就到这停。
- 4上面一排是第一个单词 "interpreter" 的每一位字符(下标固定)。我们以它为基准,从第 0 列开始,逐列去和其它单词的同一位比。公共前缀一开始是空的。
- 5比较第 0 列:基准单词这一位是 'i'。右边列出每个单词在第 0 列的字符——逐个看它们是不是都等于 'i'。
- 6第 0 列所有单词都是 'i',全相同!把 'i' 并入公共前缀,前缀变成 "i",这一列变绿,继续看下一列。
- 7比较第 1 列:基准单词这一位是 'n'。右边列出每个单词在第 1 列的字符——逐个看它们是不是都等于 'n'。
- 8第 1 列所有单词都是 'n',全相同!把 'n' 并入公共前缀,前缀变成 "in",这一列变绿,继续看下一列。
- 9比较第 2 列:基准单词这一位是 't'。右边列出每个单词在第 2 列的字符——逐个看它们是不是都等于 't'。
- 10第 2 列所有单词都是 't',全相同!把 't' 并入公共前缀,前缀变成 "int",这一列变绿,继续看下一列。
- 11比较第 3 列:基准单词这一位是 'e'。右边列出每个单词在第 3 列的字符——逐个看它们是不是都等于 'e'。
- 12第 3 列所有单词都是 'e',全相同!把 'e' 并入公共前缀,前缀变成 "inte",这一列变绿,继续看下一列。
- 13比较第 4 列:基准单词这一位是 'r'。右边列出每个单词在第 4 列的字符——逐个看它们是不是都等于 'r'。
- 14第 4 列所有单词都是 'r',全相同!把 'r' 并入公共前缀,前缀变成 "inter",这一列变绿,继续看下一列。
- 15比较第 5 列:基准单词这一位是 'p'。右边列出每个单词在第 5 列的字符——逐个看它们是不是都等于 'p'。
- 16第 5 列所有单词都是 'p',全相同!把 'p' 并入公共前缀,前缀变成 "interp",这一列变绿,继续看下一列。
- 17比较第 6 列:基准单词这一位是 'r'。右边列出每个单词在第 6 列的字符——逐个看它们是不是都等于 'r'。
- 18第 6 列所有单词都是 'r',全相同!把 'r' 并入公共前缀,前缀变成 "interpr",这一列变绿,继续看下一列。
- 19比较第 7 列:基准单词这一位是 'e'。右边列出每个单词在第 7 列的字符——逐个看它们是不是都等于 'e'。
- 20第 7 列所有单词都是 'e',全相同!把 'e' 并入公共前缀,前缀变成 "interpre",这一列变绿,继续看下一列。
- 21比较第 8 列:基准单词这一位是 't'。右边列出每个单词在第 8 列的字符——逐个看它们是不是都等于 't'。
- 22第 8 列所有单词都是 't',全相同!把 't' 并入公共前缀,前缀变成 "interpret",这一列变绿,继续看下一列。
- 23比较第 9 列:基准单词这一位是 'e'。右边列出每个单词在第 9 列的字符——逐个看它们是不是都等于 'e'。
- 24第 9 列出现不一致:单词 "interpreting" 这一位是 'i',不等于基准的 'e'。只要有一个单词不同或到头,公共前缀就到此为止——停!最终公共前缀就是 "interpret"。
- 25扫描结束:前 9 列(绿色)是所有单词都一致的部分,它们拼起来 "interpret" 就是最长公共前缀。后面的列因为出现了不一致,不再属于公共前缀。
⚠️ 容易写错的地方
✗ 错:只比相邻两个单词
✓ 对:每一列要比所有单词
相邻相同不代表全体都相同
✗ 错:忘了某个单词会先到头
✓ 对:比较前先判 col >= len(w)
短单词到头后再取字符会越界
✗ 错:空数组直接取 strs[0]
✓ 对:先判空返回空串
空输入取首元素会崩
完整代码(Python / C++ / Java)
Python
def longestCommonPrefix(strs):
if not strs: return ""
base = strs[0] # 以第一个单词为基准
for col in range(len(base)): # 逐列
ch = base[col]
for w in strs: # 比较所有单词的同一位
if col >= len(w) or w[col] != ch:
return base[:col] # 不同/到头 → 前缀到此为止
return base # 基准串本身就是公共前缀C++
string longestCommonPrefix(vector<string>& strs){
if(strs.empty()) return "";
string base = strs[0]; // 基准串
for(int col = 0; col < (int)base.size(); col++){
char ch = base[col];
for(auto& w : strs) // 比较所有单词同一位
if(col >= (int)w.size() || w[col] != ch)
return base.substr(0, col); // 不同/到头 → 停
}
return base;
}Java
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) return "";
String base = strs[0]; // 基准串
for (int col = 0; col < base.length(); col++) {
char ch = base.charAt(col);
for (String w : strs) // 比较所有单词同一位
if (col >= w.length() || w.charAt(col) != ch)
return base.substring(0, col); // 不同/到头 → 停
}
return base;
}复杂度
时间
O(n·m)
n 个单词,最坏每列都比一遍,m 为公共前缀长度
空间
O(1)
只用常数个变量,不额外开数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 最长公共前缀 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
除了纵向扫描,还有别的思路吗?+
横向扫描:先拿前两个单词求公共前缀,再用结果和第三个比、依次缩短;还可以排序后只比首尾两个单词(排序后最大差异落在首尾),或用分治/二分前缀长度。纵向扫描最直观,且能一发现不同就早停。
为什么可以只以第一个单词为基准?+
公共前缀一定是每个单词的前缀,自然也是第一个单词的前缀,长度不会超过它。所以以第一个单词逐列推进,配合「其它单词到头/不同就停」即可,不会漏也不会多。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 最长公共前缀 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。