编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入: ["flower","flow","flight"] 输出: "fl"
示例 2:
输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z
。
方法一、
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length==0||strs[0].length()==0)
return "";
String res=strs[0];
for(int i=1;i<strs.length;i++){
int l=0;
while(l<res.length()&&l<strs[i].length()&&res.length()>0){
if(res.charAt(l)!=strs[i].charAt(l)){
res=res.substring(0,l);
continue;
}
l++;
}
res=res.substring(0,l>res.length()?res.length():l);
}
return res;
}
}
方法二、
水平扫描法
时间复杂度:O(S),S是所有字符串中字符数量的总和。
最坏的情况下,n个字符串都是相同的。算法会将S1与其它字符串[S2....Sn]都做一次比较。这样就会进行S次字符比较,其中S是输入数据中所有的字符数量。
空间复杂度:O(1),我们只需要使用常数级别的额外空间。
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs.length == 0) return "";
String prefix = strs[0];
for (int i = 1; i < strs.length; i++)
while (strs[i].indexOf(prefix) != 0) {
prefix = prefix.substring(0, prefix.length() - 1);
if (prefix.isEmpty()) return "";
}
return prefix;
}
}
方法三、
分治
思路
这个算法的思路来自于LCP操作的结合律。 我们可以发现: LCP(S1…Sn)=LCP(LCP(S1…Sk),LCP(Sk+1…Sn))LCP(S_1 \ldots S_n) = LCP(LCP(S_1 \ldots S_k), LCP (S_{k+1} \ldots S_n))LCP(S1…Sn)=LCP(LCP(S1…Sk),LCP(Sk+1…Sn)) ,其中 LCP(S1…Sn)LCP(S_1 \ldots S_n)LCP(S1…Sn) 是字符串 [S1…Sn][S_1 \ldots S_n][S1…Sn] 的最长公共前缀,1<k<n1 < k < n1<k<n。
算法
为了应用上述的结论,我们使用分治的技巧,将原问题 LCP(Si⋯Sj)LCP(S_i\cdots S_j)LCP(Si⋯Sj) 分成两个子问题 LCP(Si⋯Smid)LCP(S_i\cdots S_{mid})LCP(Si⋯Smid) 与 LCP(Smid+1,Sj)LCP(S_{mid+1}, S_j)LCP(Smid+1,Sj) ,其中 mid
=i+j2\frac{i+j}{2}2i+j。 我们用子问题的解 lcpLeft
与 lcpRight
构造原问题的解 LCP(Si⋯Sj)LCP(S_i \cdots S_j)LCP(Si⋯Sj)。 从头到尾挨个比较 lcpLeft
与 lcpRight
中的字符,直到不能再匹配为止。 计算所得的 lcpLeft
与 lcpRight
最长公共前缀就是原问题的解 LCP(Si⋯Sj)LCP(S_i\cdots S_j)LCP(Si⋯Sj)
复杂度分析:
最坏的情况下,我们有n个长度为m的相同字符串。
时间复杂度:O(S),S是所有字符串中字符数量的总和 S=m*n.
时间复杂度的递推式为T(n)=2*T(n/2)+O(m),化简后可知是O(S).最好情况下,算法会进行minLen*n次比较其中minLen是数组中最短字符串的长度。
空间复杂度:O(m*log(n)).内存开支主要是递归过程中使用的栈空间所消耗的。一共会进行log(n)次递归,每次需要m的空间存储返回结果,所以空间复杂度为O(m*log(n))
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length==0)
return "";
return getLongestCommonPrefix(strs,0,strs.length-1);
}
private String getLongestCommonPrefix(String[]strs,int l,int r){
if(l==r){
return strs[l];
}
int mid=l+(r-l)/2;
//[0,mid] [mid+1,r]
String left=getLongestCommonPrefix(strs,l,mid);
String right=getLongestCommonPrefix(strs,mid+1,r);
return commonPrefix(left,right);
}
private String commonPrefix(String left,String right){
int min=Math.min(left.length(),right.length());
for(int i=0;i<min;i++){
if(left.charAt(i)!=right.charAt(i)){
return left.substring(0,i);
}
}
return left.substring(0,min);
}
}