题目:最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入:
strs = ["flower","flow","flight"]
输出:
"fl"
示例 2:
输入:
strs = ["dog","racecar","car"]
输出:
""
这道题重点词是 “前缀”,即我们要寻找的公共子串部分是在每个单词index=0的位置开始累计的
法一:暴力解法
思路
result:记录最终的前缀字符串
flag:标志位,记录当前字符串是否符合我们的要求
temp:候选字符串
因为提取的是前缀字符串,所以我们就选择strs数组中第一个元素作为基准。
外层循环 遍历strs中第一个元素的每个字母,这里我们用temp来存储累计的字符串。
那么内层循环遍历的是strs中的各个元素(即题目中strs数组的整个单词),判断 :
-
如果候选字符串temp在各个元素的下标0位置都存在,那么这个候选字符串temp是成立的。且这个候选字符串的长度大于result字符串的长度,就将temp赋值给result。
-
如果strs有任何一个元素头部并不符合候选字符串temp,那么给标志位赋一个false跳出内层循环(不再遍历判断strs之后的元素)。这时,再判断一次flag,并跳出外层循环(此时已计算出最长的前缀和)
图解
例如,题目中第一组数据中:
i = 0 时, temp = 'f';
strs[1]和strs[2]头部前缀符合temp,flag=true,进入下一次循环
- 因为上一次循环flag 为true,此时temp应加上strs[0]的后一个字母,即
i = 1 时, temp = 'fl';
strs[1]和strs[2]头部前缀符合temp,flag=true,进入下一次循环
- 同理,
i = 2 时, temp = 'flo';
但此时,strs[2]中却不符合temp的前缀和了,所以直接跳出循环,不将这次temp赋值给最终结果。
代码
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
var result = '';
var temp = '';
var flag = true;
for (var i = 0; i < strs[0].length; i++) {
temp += strs[0][i];
for (var j = 1; j < strs.length; j++) {
if (strs[j].indexOf(temp) !== 0) {
flag = false;
break;
}
}
if (flag && (temp.length > result.length)) {
result = temp;
} else {
break;
}
}
return result.length > 0? result:"";
};
后面一想,这里其实根本不用判断result和temp的长度,既然前缀和一定是从0开始计算,那么候选字符串temp的长度后一个总是比前一个更长的。
所以可以把 (temp.length > result.length) 长度判断去掉
法二:两两对比法
思路
首先选取strs第一个元素作为ans(比较字符串),然后将strs剩下的所有元素和ans都两两比较一遍,在每次比较中都截取头部相同的字符串部分。
图解
-
将strs[0]作为and,比较字符串,剩下两个分别为strs[1],strs[2]
-
第一次将ans与strs[1]比较,发现相同的是"flo",故此时ans变为"flo"(红框圈起部分)
-
第二次将ans与strs[2]比较,相同字符串为"fl"此时ans变为"fl"
经过两次比较之后,最终的最长公共前缀就出来, 就是"fl"
代码
/**
* @param {string[]} strs
* @return {string}
* 解法:两两比较
*/
var longestCommonPrefix = function(strs) {
var ans = strs[0];
for (var i = 1; i < strs.length; i++) {
for (var j = 0; j < strs[i].length && j < ans.length; j++) {
if (strs[i][j] !== ans[j]) {
break;
}
}
ans = ans.substring(0, j);
if (ans.length == 0) {
return "";
}
}
return ans;
};