14.最长公共前缀
Posted summerday152
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了14.最长公共前缀相关的知识,希望对你有一定的参考价值。
14.最长公共前缀
题目描述
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。(所有输入只包含小写字母 a-z )
官方题解
水平扫描
解题思路:将第一个字符串作为暂时的公共前缀,往后遍历,逐渐得到所有字符串的公共前缀。
public static String longestCommonPrefix00(String[] strs){
if(strs==null||strs.length==0) return "";//传进空数组
//将第一个字符串作为暂时作为公共前缀
String prefix = strs[0];
for (int i = 1; i < strs.length ; i++) {
while(strs[i].indexOf(prefix)!=0){//不等于0说明第一个字符串并不是该字符串的前缀,则向前推移
//prefix.substring(0,prefix.length()-1) 除去该字符串的最后一个字符
prefix = prefix.substring(0,prefix.length()-1);
//取到第一个字符,还是没有公共前缀,返回“”
if(prefix.isEmpty()) return "";
}
}
return prefix;
}
复杂度分析
时间复杂度:O(S),S 是所有字符串中字符数量的总和。
最坏的情况下,n 个字符串都是相同的。算法会将 S1 与其他字符串都做一次比较。这样就会进行 S 次字符比较,其中 S 是输入数据中所有字符数量。
空间复杂度:O(1),我们只需要使用常数级别的额外空间。
垂直扫描
解题思路:
从前往后枚举字符串的每一列,先比较每个字符串相同列上的字符(即不同字符串相同下标的字符)然后再进行对下一列的比较。
public static String longestCommonPrefix01(String[] strs){
if(strs==null||strs.length==0) return "";
//该for循环表示从前往后遍历比较某一个字符串每个位上的字符
for(int i = 0;i<strs[0].length();i++){
char c = strs[0].charAt(i);
//该for循环表示从第二个字符串开始,从前往后遍历传入数组中的每个字符串
for(int j = 1;j<strs.length;j++){
// 两个判断条件:i
// 1.i==strs[j].length()
// i表示第一个字符串的位数,如果i和后面字符串的长度相等,就不对(位数是从0开始计数的,长度从1开始的)
// 2.strs[j].charAt(i)!=c
// 后面的字符串在相同位数时,字符不一致,即不对。
// 两者情况任一满足一个,就返回第一个字符串0~i-1位数的字符串
if(i==strs[j].length()||strs[j].charAt(i)!=c){
//public String substring(int beginIndex,int endIndex)
//返回一个字符串,该字符串是此字符串的子字符串。
// 子串开始于指定beginIndex并延伸到字符索引endIndex - 1 。
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
复杂度分析:
- 时间复杂度:o(s),s是所有字符串的总字符数。
最坏的情况,输入n个长度为m的相字符串,s=nm。最坏的情况和第一种一样,但是最好的情况下,只需要进行[字符串个数][最短字符串的长度]次数的比较。 - 空间复杂度:o(1),只需要常数级别的额外空间。
分治解法
解题思路:即将所有字符串拆分,每一部分的公共前缀的公共前缀,必然是所有字符串的公共前缀。
public static String longestCommonPrefix02(String[] strs){
if(strs == null||strs.length==0) return "";
return longestCommonPrefix(strs,0,strs.length-1);
}
private static String longestCommonPrefix(String[] strs,int left,int right){
//跳出递归的情况
if(left==right){
return strs[left];
}
else{
//分治
int mid = (left+right)/2;
String lcpLeft = longestCommonPrefix(strs,left,mid);
String lcpRight = longestCommonPrefix(strs,mid+1,right);
return CommonPrefix(lcpLeft,lcpRight);
}
}
//普通比较两个字符串的最长前缀的方法,按字符比较,最多是到其中较短的字符串的长度位数位置
private static String CommonPrefix(String left,String right){
//min变量存储较短字符串的长度
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);
}
//跳出for循环,说明较短的字符串就是公共前缀
return left.substring(0,min);
}
复杂度分析:
- 时间复杂度:o(s),s是所有字符串的总字符数。
最坏的情况,输入n个长度为m的相字符串。但是最好的情况下,只需要进行[字符串个数]*[最短字符串的长度]次数的比较。 - 空间复杂度:o(mlog(n))
内存开支主要是递归过程中使用栈空间所消耗。log(n)次递归,每次需要m的空间存储返回结果。
二分查找
解题思路:最短字符串的长度就是公共前缀的最大可能长度。将字符串一分为二,每次经过判断,丢弃一部分,最终找到公共前缀。
public static String longestCommonPrefix03(String[] strs){
if(strs==null||strs.length==0) return "";
int minLen = Integer.MAX_VALUE;
//最长公共前缀的最大可能长度就是最短的字符串长度
//找出字符串数组中最短字符串的长度 minLen
for(String str:strs)
minLen = Math.min(minLen,str.length());
int low = 1;
int high = minLen;
while(low<=high){
//将查找空间一分为二
int mid =(low+high)/2;
//如果第一个字符串前面一半字符是所有串的公共前缀,那么就可以丢弃前一半查找空间
if(isCommonPrefix(strs,mid))
low = mid +1;
//如果不是的话,丢弃后一半
else
high = mid -1;
}
//找到最长前缀的最后位置,并返回
return strs[0].substring(0,(low+high)/2);
}
//判断传入数组的第一个字符串的前len位是不是后面的前缀,是返回true, 不是返回false
private static boolean isCommonPrefix(String[] strs,int len){
String str1 = strs[0].substring(0,len);
for (int i = 1; i < strs.length; i++) {
if(!strs[i].startsWith(str1))
return false;
}
return true;
}
复杂度分析:
- 时间复杂度:o(s·log(n)),s是所有字符串的总字符数。
最坏的情况,输入n个长度为m的相字符串。一共进行log(n)次迭代,每次都会进行s次比较。 - 空间复杂度:o(1),只需要常数级别的额外空间。
以上是关于14.最长公共前缀的主要内容,如果未能解决你的问题,请参考以下文章
2021-09-15:最长公共前缀。编写一个函数来查找字符串数组中的最长公共前缀,如果不存在公共前缀,返回空字符串 ““。力扣14。