难度:中等
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
方法一:(暴力法/水平扫描法)
看到这个题之后,我的第一想法是直接进行比较,也就是暴力法,但是数组中字符串的长度不定,肯定不可能写尽循环,于是我想到了“1和2比,得到公共前缀存起来,然后再用1和2的公共前缀和3比……以此类推,当result为空的时候,就直接停止循环,并返回result(最开始的时候,我没有做判result为空这一步,是看了官方题解之后加的)”。
class Solution {
public String twoStringfindSame(String str1,String str2){
int minLen = str1.length()<str2.length()?str1.length():str2.length();
String result = "";
for(int i = 0;i<minLen;i++){
if(str1.charAt(i)!=str2.charAt(i))
break;
else
result += str1.charAt(i);
}
return result;
}
public String longestCommonPrefix(String[] strs) {
int len = strs.length;
if(strs.length==0 || strs==null){
return "";
}
String result = strs[0];
for(int i=1;i<len;i++){
if(result=="")
return "";
else
result = twoStringfindSame(result,strs[i]);
}
return result;
}
}
这种简单粗暴的方式……果然,时间和空间方面效率都太差了。像个憨憨。
然后看了官方题解之后我发现,我这个思路是和官方题解的方法一——水平扫描法思路(其实就是暴力法)一致,可是官方题解的代码非常精妙……!!
官方的这个暴力解法,可以称之为最棒的暴力解法。
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) {
//不等于0,就说明是-1,没有从头就找到对应的子串,
//于是使用substring函数,将prefix串减掉最后一个字符
prefix = prefix.substring(0, prefix.length() - 1);
if (prefix.isEmpty())
return "";
}
}
return prefix;
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间方面提高了很多。同样都是暴力解法,人与人差别太大了。
知识盲点:
indexOf() 方法有以下四种形式:
- public int indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
- public int indexOf(int ch, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
- int indexOf(String str): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。 ★ ★ ★
- int indexOf(String str, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
官方题解中的使用,使用的是第三种形式。
看到另一位精选题解,思想相同,但这个代码更通俗易懂。效果也很不错。
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0)
return "";
String ans = strs[0];
for(int i =1;i<strs.length;i++) {
int j=0;
//原答主用的是for循环,我觉得while看着顺眼并想和官方题解做一个对比。
//for(;j<ans.length() && j < strs[i].length();j++)
while(j<ans.length() && j < strs[i].length()){
if(ans.charAt(j) != strs[i].charAt(j)){
break;
}
j++;
}
ans = ans.substring(0, j);
if(ans.equals(""))
return ans;
}
return ans;
}
}
作者:guanpengchn
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/hua-jie-suan-fa-14-zui-chang-gong-gong-qian-zhui-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析:
-
时间复杂度: O ( S ) O(S) O(S), S S S是所有字符串中字符数量的总和。
最坏的情况下, n n n个字符串都是相同的。算法会将 S 1 S1 S1与其他字符串 [ S 2 … S n ] [S_2…S_n] [S2…Sn]都做一次比较。这样就会进行 S S S次字符比较,其中 S S S是输入数据中所有字符数量。 -
空间复杂度: O ( 1 ) O(1) O(1),我们只需要使用常数级别的额外空间。
附:水平扫描法的Python解答
-
知识扩充:
- Python中的find()方法检测字符串中是否包含子字符串s 。
- 如果包含子字符串返回开始的索引值,否则返回-1。
- 如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内
- 语法:
str.find(str, beg=0, end=len(string))
- str – 指定检索的字符串
- beg – 开始索引,默认为0。
- end – 结束索引,默认为字符串的长度。
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if len(strs) == 0:
return ''
s = strs[0]
for i in range(1, len(strs)):
while strs[i].find(s) != 0 :
s = s[:-1] #列表切片,每次长度减一
return s
作者:huamei
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/python-shui-ping-sao-miao-fa-by-huamei/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二:(纵向扫描法)
方法三:(分治法)
方法四:(二分查找法)
方法二三四均来自官方题解,附上链接
https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode/