一 题目描述
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"] 输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"] 输出:"" 解释:输入不存在公共前缀。
二 方法代码
-
方法一
public String longestCommonPrefix(String[] strs) {
if(strs == null || strs.length == 0) {
return "";
}
String prefix = strs[0];
int len,index;
//比较第一个和第二个字符串的公共前缀,然后拿着结果再和第三个比较,再和第四个比较...
for(int i = 1; i < strs.length; i++) {
len = Math.min(prefix.length(), strs[i].length());
//(prefix.length() > strs[i].length()) ? strs[i].length() : prefix.length();
index = 0;
//len代表两个字符串中最短的长度,这样避免溢出
//index表示从第一个字符开始比较两个字符串中有多少位字符一样
//得到两个字符串中最长前缀的位数,然后最后统一取出
while(index < len && prefix.charAt(index) == strs[i].charAt(index)) {
index++;
}
prefix = prefix.substring(0, index);
if(prefix.isEmpty()) {
break;
}
}
return prefix;
}
-
方法二
public String longestCommonPrefix1(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
//求字符串数组中最短的字符串长度
int minLength = strs[0].length();
for(String str : strs) {
if(str.length() < minLength) {
minLength = str.length();
}
}
int index = 0;
//按列比较每个字符串的字符是否一致
while(index < minLength) {
//flag表示if语句执行,即出现了字符不一致的情况,跳出while
boolean flag = true;
for(int i = 0; i < strs.length - 1; i++) {
if(strs[i].charAt(index) != strs[i + 1].charAt(index)) {
flag = false;
break;
}
}
if(!flag) {
break;
}
index++;
}
return strs[0].substring(0, index);
}
-
方法三
这个方法力扣官方说叫分治,就是把问题分为更小的子问题解决,其实我更愿意叫它递归,他的原理如图:
public String longestCommonPrefix2(String[] strs) {
if(strs == null || strs.length == 0) {
return "";
}else{
return function(strs, 0, strs.length - 1);
}
}
public String function(String[] strs, int start, int end) {
if(start == end){
//这种情况说明只有一个字符串了,就返回这个字符串给上一级
//返回之后和另一半返回的同样只剩下一个的字符串比较公共前缀,然后再返回给上一级
return strs[start];
}else{
//这种情况说明还可以分开两半,就继续分,直到分到不能分,然后挨个返回
int mid = start + (end - start)/2;
String left = function(strs, start, mid);
String right = function(strs, mid + 1, end);
return getPrefix(left,right);
}
}
public String getPrefix(String left, String right) {
int minLength = Math.min(left.length(), right.length());
for (int i = 0; i < minLength; i++) {
if (left.charAt(i) != right.charAt(i)) {
return left.substring(0, i);
}
}
return left.substring(0, minLength);
}
-
方法四
public String longestCommonPrefix3(String[] strs){
//很巧妙的方法,字符串排序,比较第一个和最后一个的公共前缀
//但是不建议一解题就排序,排序的时间复杂度会比较高
Arrays.sort(strs);
String prefix = "";
//遍历第一个和最后一个字符串的每一个字符,
//并且i不能超过两个字符串中较短字符串的长度,否则会溢出
for(int i = 0; i < strs[0].length() && i < strs[strs.length-1].length(); i++){
if(strs[0].charAt(i) == strs[strs.length-1].charAt(i)){
prefix = prefix + strs[0].charAt(i);
}else {
break;
}
}
return prefix;
}
三 性能分析和比较
方法一和二都是:
时间复杂度:O(S),其中S是所有字符串中字符数量的总和。在最坏情况下,需要比较每个字符。
方法三是:
复杂度也是O(S)
,但由于其使用了分治法,通过将问题分成较小的子问题来解决,每次递归调用的字符串数量减半,每次只比较两个字符串的公共前缀,减少了不必要的比较次数。相比之下,方法一需要每次比较所有字符串,效率较低。分治法更快的原因主要在于其减少了不必要的比较次数,
方法四是:
排序太慢了