一、题目描述
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"] 输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"] 输出:"" 解释:输入不存在公共前缀。
提示:
1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i]
仅由小写英文字母组成
二、解题思路
- 如果数组为空或者只有一个元素,直接返回该元素(或者空字符串,如果只有一个空字符串)。
- 初始化一个变量来存储当前的最长公共前缀。
- 遍历数组中的每个字符串,从第一个字符串开始,逐个字符与最长公共前缀进行比较。
- 对于每个字符串,从第一个字符开始,比较它与当前最长公共前缀的对应字符是否相同。如果不同,更新最长公共前缀为当前匹配到的字符。
- 如果在比较过程中发现某个字符串的某个字符与当前最长公共前缀不匹配,那么这个字符就是最长公共前缀的结束位置。
- 如果在比较过程中,最长公共前缀变成了空字符串,说明没有公共前缀,直接返回空字符串。
- 如果遍历完所有字符串后,最长公共前缀仍然是有效的,那么这个最长公共前缀就是答案。
三、具体代码
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
// 如果只有一个字符串,直接返回该字符串
if (strs.length == 1) {
return strs[0];
}
String prefix = strs[0];
// 遍历数组中的每个字符串
for (int i = 1; i < strs.length; i++) {
int j = 0;
while (j < prefix.length() && j < strs[i].length() && prefix.charAt(j) == strs[i].charAt(j)) {
j++;
}
// 更新最长公共前缀
prefix = prefix.substring(0, j);
// 如果最长公共前缀为空,说明没有公共前缀
if (prefix.isEmpty()) {
return "";
}
}
return prefix;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 时间复杂度:O(n * m)。
- 时间复杂度主要取决于两个循环。
- 外层循环遍历数组中的字符串,内层循环比较当前最长公共前缀与数组中其他字符串的对应字符。
- 在最坏的情况下,每个字符串的长度都相同,且最长公共前缀的长度随着比较逐渐减小。
- 假设字符串的平均长度为
m
,数组中有n
个字符串。 - 外层循环执行
n
次,内层循环在最坏情况下执行m
次。 - 因此,时间复杂度为 O(n * m)。
2. 空间复杂度
- 空间复杂度:O(1)。
- 空间复杂度主要考虑变量的存储。
- 除了输入的字符串数组和返回的最长公共前缀之外,我们只使用了两个变量(
j
和prefix
)来进行比较和更新。 - 这些变量的空间需求是常数级别的。
- 因此,空间复杂度为 O(1)。
五、总结知识点
1. 条件判断:
- 使用
if
语句来检查输入数组是否为空或者只有一个元素,以及是否需要返回空字符串。
2. 循环控制:
- 使用
for
循环遍历字符串数组,这是处理数组元素的常用方法。 - 在循环中使用
int j
作为索引变量,用于比较字符串的字符。
3. 字符串操作:
- 使用
charAt()
方法来获取字符串中特定位置的字符。 - 使用
substring()
方法来截取字符串的一部分,这里用于更新最长公共前缀。
4. 递归比较:
- 在内层循环中,通过比较当前最长公共前缀与数组中其他字符串的对应字符,逐步缩小最长公共前缀的长度。
5. 边界条件处理:
- 在比较过程中,如果最长公共前缀变为空字符串,说明没有公共前缀,此时返回空字符串。
6. 代码风格:
- 代码遵循了良好的命名习惯,如
prefix
用于表示最长公共前缀,j
作为循环索引。 - 使用了注释来提高代码的可读性,解释了代码的逻辑。
7. 异常处理:
- 在处理可能的空输入时,代码正确地返回了空字符串,避免了潜在的
NullPointerException
。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。