问题描述
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例
输入: ["flower","flow","flight"]
输出: "fl"
输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
问题分析
一个显而易见的思路就是,找到一个最短的串,判断它是不是序列中所有串的子串,如果是,则返回;如果不是,则它的长度缩减1,继续遍历判断。时间复杂度O(n*m)
(方法一)。
长度逐渐缩减1,听着怎么这么像二分查找?我们可以用二分查找的思想来找到答案。二分查找到自动退出的前一个循环时,left肯定等于right。所以如果最后一次循环的结果,符合前缀条件,那么最后肯定要返回mid。如果不符合前缀条件,那么要返回mid-1。咦,好麻烦,为什么还要判断符不符合条件?你不想判断也可以,因为你的退出条件是left>right,即left = right + 1。 如果符合前缀条件,left就是mid+1,要返回left-1. 返回left-1就相当于返回(left+right)/2, 为啥?因为此时right=mid. 所以left+mid = 2mid+1. 所以(2mid+1)/2 = mid;同理,不符合前缀条件时,返回mid-1。此时right就等于mid-1,则left+right= 2mid-1, (2mid-1)/2 = mid - 1. 所以我们只需要返回(left+right)/2就行了。时间复杂度O(n*log(m))
(方法二)
也可以假定第一个串就是最长公共前缀,用这个串去匹配每一个元素,如果它不是某个元素的前缀,那么就把这个串长度缩减1,还不是,继续缩减1,直到缩减到符合这个元素的最长前缀才继续搜索下一个元素。如果这个假定的串长度缩减为0,就代表找不到公共前缀了,直接返回。时间复杂度O(m+n)
。(方法三)
也可以这样,我们想象一下,把字符串数组中的每个字符串,每个字符串占一行排好,我们会发现我们也可以先对比这些串的第一个元素,符合则继续,不符合则return之前的结果。这样我们的时间复杂度就是O(n*m)
。 (方法四)
解法一Java版
public String longestCommonPrefix(String[] strs) {
String res = "";
if(strs.length == 0){
return res;
}else if(strs.length == 1){
return strs[0];
}
String targetStr = findMinStr(strs);
for(int left = targetStr.length(); left>0; left--){
boolean flag = true;
for(String st: strs){
if(!st.startsWith(targetStr.substring(0,left))){
flag = false;
break;
}
}
if(flag){
res = targetStr.substring(0,left);
break;
}
}
return res;
}
private String findMinStr(String[] strs){
int res = 0;
for(int i = 1; i < strs.length; i++){
if(strs[res].length() > strs[i].length()){
res = i;
}
}
return strs[res];
}
解法二Java版
private String findMinStr(String[] strs){
int res = 0;
for(int i = 1; i < strs.length; i++){
if(strs[res].length() > strs[i].length()){
res = i;
}
}
return strs[res];
}
public String longestCommonPrefix1(String[] strs) {
String res = "";
if(strs.length == 0){
return res;
}else if(strs.length == 1){
return strs[0];
}
String targetStr = findMinStr(strs);
int left = 1,right = targetStr.length(),mid=(left+right)/2;
boolean flag = true;
while(left <= right){
mid=(left+right)/2;
flag = true;
for(String st: strs){
if(!st.startsWith(targetStr.substring(0,mid))){
flag = false;
break;
}
}
if(flag){
left = mid+1;
}else{
right = mid-1;
}
}
return targetStr.substring(0,(left+right)/2);
}
解法三Java版
public String longestCommonPrefix2(String[] strs){
if(strs.length == 0){
return "";
}
String prefix = strs[0];
for(String st: strs){
while(!st.startsWith(prefix)){
prefix = prefix.substring(0,prefix.length()-1);
}
if(prefix.length() == 0){
return "";
}
}
return prefix;
}
解法四Java版
public String longestCommonPrefix3(String[] strs){
if(strs.length == 0){
return "";
}else if(strs.length == 1){
return strs[0];
}else if(strs[0].length() == 0){
return "";
}
String prefix = strs[0];
char curs = prefix.charAt(0);
int index = 0;
for(int i = 0; i < prefix.length(); i++){
curs = prefix.charAt(i);
for(String st: strs){
if(st.length()<=i || st.charAt(i)!=curs){
return prefix.substring(0,i);
}
}
}
return prefix;
}