一、题目描述
给一组字符串,找出它们共同的开头部分。
比如:
python
strs = ["flower", "flow", "flight"]
三个字符串都以 "fl" 开头,第 3 位开始不同,所以答案是 "fl"。
flower
flow
flight
------
fl ← 公共前缀
如果没有任何公共开头,返回空字符串。
二、核心思路
把所有字符串排成几行,一列一列地比。
从第 0 列开始,拿第一个字符串的字符作为标准,去和所有字符串的同一位比较:
-
如果这一列全都相同,就把这个字符收进结果;
-
一旦出现不同,立刻停止,返回已经收集到的结果。
f l o w e r
f l o w
f l i g h t
↑ ↑ ↑
0 1 2 ← 第 2 列不同,停
第 0 列都是 f,第 1 列都是 l,第 2 列出现 o 和 i 不同,停止。结果是 "fl"。
三、代码实现
python
class Solution:
def longestCommonPrefix(self, strs: list[str]) -> str:
if not strs:
return ""
# 1. 找最短字符串长度,作为比较上限
min_len = min(len(s) for s in strs)
res = []
# 2. 一列一列比
for i in range(min_len):
c = strs[0][i] # 拿第一个字符串的第 i 位当标准
for s in strs: # 和所有字符串的第 i 位比
if s[i] != c:
return "".join(res) # 出现不同,立即返回
res.append(c) # 这一列全相同,收进结果
return "".join(res)
四、逐段讲解
1. 空输入处理
python
if not strs:
return ""
列表为空时没有公共前缀,直接返回空字符串。
2. 找最短长度
python
min_len = min(len(s) for s in strs)
公共前缀不可能比最短的字符串还长。比如 ["ab", "abc"],最短长度是 2,最多比到第 2 位。
这一步既是比较上限 ,也防止后面 s[i] 越界。
3. 逐列比较
python
for i in range(min_len):
c = strs[0][i]
for s in strs:
if s[i] != c:
return "".join(res)
res.append(c)
c是这一列的"标准",取第一个字符串的第i位。- 内层
for拿c去和每个字符串的第i位比。 - 一旦有不同,说明公共前缀到此为止,直接返回已收集的结果。
- 如果这一列全相同,把
c加进res,继续下一列。
4. 返回结果
python
return "".join(res)
res 是字符列表,用 join 拼成字符串。
五、手动走一遍例子
以 strs = ["flower", "flow", "flight"] 为例:
| 轮次 | i | c | 比较结果 | res |
|---|---|---|---|---|
| 1 | 0 | f |
都是 f ✅ |
['f'] |
| 2 | 1 | l |
都是 l ✅ |
['f','l'] |
| 3 | 2 | o |
flight[2]='i' ❌ |
返回 "fl" |
第 2 列出现不同,函数提前返回 "fl"。
六、复杂度分析
- 时间:O(n × m),n 是字符串个数,m 是最短字符串长度。最坏情况要比 m 列,每列比 n 个字符串。
- 空间 :O(m),
res最多存 m 个字符。
七、易错点
- 不先求最短长度 :直接
strs[0][i]可能越界,比如["ab", "abc"]比到第 2 位就崩了。 - 空列表 :
strs = []要返回""。 - 单字符串 :
strs = ["abc"],公共前缀就是它自己。 - 空字符串 :
strs = ["", "abc"],最短长度 0,循环不执行,返回""。 flag写法 vs 提前 return :用flag标记逻辑对,但用return提前退出更简洁。
八、原版 vs 简化版
原版(用 flag 控制):
python
while first < l:
c = strs[0][first]
flag = True
for s in strs:
if s[first] != c:
flag = False
break
if not flag:
break
same.append(c)
first += 1
return "".join(same)
简化版(提前 return):
python
for i in range(min_len):
c = strs[0][i]
for s in strs:
if s[i] != c:
return "".join(res)
res.append(c)
return "".join(res)
两者思路完全一致。原版用 flag 控制跳出,简化版直接 return,少一层判断。
九、总结
纵向扫描的核心是一列一列比。先找最短长度确定比较上限,然后从第 0 列开始,拿第一个字符串的字符去和所有字符串的同一位比较,全都相同就收集,遇到不同就停。
优点是直观、容易理解;缺点是每次都要遍历所有字符串。
时间复杂度 O(n × m),空间复杂度 O(m)。