编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
提示:
- 0 <=
strs.length
<= 200 - 0 <=
strs[i].length
<= 200 strs[i]
仅由小写英文字母组成
思路
这题看上去简单,但是坑实在是太多了,前前后后提交了7次才AC,只能说自己的心思还是不够缜密,通过率狂掉……
一开始的想法是既然是找公共子串,那不就是给定的几个字符串之间的交集嘛,于是选择了用LinkedHashSet
来做,每次读入一个字符串求一下交集,结果发现自己还是太年轻,遇到诸如["aa", "aa"]
这种情况就会只输出一个"a"
。因此,本题并不能用集合来做,因为子串允许重复数据的存在,而集合不允许。
然后就干脆用笨办法做了:先读入一个字符串,存在sBuffer里,然后再读之后的字符串。
这里我设了一个int
型变量index
,用来标记最早出现的不同字符的位置,方便最后的sBuffer.delete()
操作。
所以,当访问后面字符串的时候(从第二个开始),如果当前位和sBuffer
的当前位一样,那说明是公共子串的一部分,直接continue
即可,如果不一样,就需要更新index
为当前位置,并且break
掉内循环,继而读下一个字符串。
这里要注意一些有关index
的逻辑问题:
- 最好
index
的初值不要赋0,因为公共子串的话自然是越短越好,我们希望每次读完一个字符串的时候,index
的位置更新的越前面越好,如果是0
的话,碰到["aa", "aa"]
这类的情况,就压根不会改变index
的值,并且还进入了sBuffer.delete()
操作(此时index = 0
),导致最后全部删完。因此,index
的初始值最好赋一个很大的数,这样每次更新就会使index
越来越小,得到的也就是最终所有字符串的公共子串了。 - 另外,在更新
index
的时候不能盲目更新,因为index = j
这个操作是直接赋值,如果后一次读入的j
反而比之前存储的index
要大(也就是更靠后一点),那么就无需再更新。因为如果不判断就直接更新的话,会造成面对诸如["aac", "cab", "abb"]
这样的字符串,index
在读最后一个字符串时会更新在1
这个位置(而实际上应该是0
)。因此,更不更新index
也是需要判断的。
代码
public class Solution {
static int MAX = 123123123;
public int findMinimumLength(String[] strs) {
int min = strs[0].length();
for(int i=1;i<strs.length;i++) {
if(strs[i].length()<min) min = strs[i].length();
}
return min;
}
public String longestCommonPrefix(String[] strs) {
StringBuffer sBuffer = new StringBuffer();
int minLength = findMinimumLength(strs);
int index = MAX;//记录第一个不同字符的位置
for(int i=0;i<minLength;i++) {
sBuffer.append(strs[0].charAt(i));
}
for(int i=1;i<strs.length;i++) {
for(int j=0;j<minLength;j++) {
if(strs[i].charAt(j)==sBuffer.charAt(j)) {
continue;
}
else {
if(j<index) index = j;//如果index的位置更前,则更新,否则不更新
break;
}
}
}
if(index<sBuffer.length()&&strs.length>=2) {
sBuffer.delete(index, sBuffer.length());
}
String answear = sBuffer.toString();
return answear;
}
}