起因
前几天接触到leetcode,开始写算法,在刷到最长公共前缀时,想到了一种奇怪的解法,所以记录下来。
题目描述
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"] 输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"] 输出:""
解释:输入不存在公共前缀。
提示:
1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i] 仅由小写英文字母组成
题解
var longestCommonPrefix = function(strs) {
if (!strs.length) return ""; //如果数组为空,返回空字符串
for (let i = 0; i < strs[0].length; i++) { //外层循环遍历第一个字符串中的每个字符
const char = strs[0][i]; //获取第一个字符串的第i个字符
for (let j = 1; j < strs.length; j++) { //内层循环遍历后续每个字符串
//如果已经超过了某个字符串的长度,
//或者第j个字符串的第i个字符与第一个字符串第i个字符不同
if (i == strs[j].length || strs[j][i] !== char) {
return strs[0].substring(0, i); //返回第一个字符串的0到i-1的子串
}
}
}
return strs[0]; //如果所有字符串都是第一个字符串的前缀,返回第一个字符串
};
这是一个比较普遍的解法,以第一个字符串(假设为A)为基准,将A的每一个位置的字符与后续每一个字符串的对应位置进行比较:
以 ["flower","flow","flight"]为例,先取出第一项的第一个字符f,然后比较后面每一项的第一个字符当比较到第三项时,发现第三个字符串
flight的第三项是i,与第一项flower的o不一致,表示第一个字符串的前两项是公共子串
华点
我突然想到一个方向,众所周知,在js中,对象的key只能是字符串或者symbol(symbol在此不是重点)是唯一的,那么我可以在上述题解的基础上修改一下,将每个字符串的每一项都注入对象,成为对象的key(属性值任意),然后比较对象自有属性的数量是否为1,如果大于1,则表示当前位置不是公共子串。
代码如下:
var longestCommonPrefix = function(arr) {
//如果输入的数组为空,或者数组的第一个字符串为空字符串,直接返回空字符串。
if (arr == null || arr[0].length == 0) return "";
//声明一个对象,用于保存前缀
let obj = {};
//外层循环,遍历第一个字符串的每一个字符
for (let i = 0; i < arr[0].length; i++) {
//以当前前缀作为键,将其保存到对象中,值为true
//这里利用了Object的键唯一性,如果后续的字符串有与之相同的前缀,
//由于键冲突,不会在对象中增加新的元素,
//可以取前i个,也可以一个一个的取,那么后续内层循环里面就相应取值就行
obj[arr[0].slice(0, i + 1)] = true;
//obj[arr[0][i+1]] = true
//内层循环,遍历剩余的字符串
for (let j = 1; j < arr.length; j++) {
//如果当前索引已经超过了某个字符串的长度,说明该字符串到头了,
//返回当前的最大公共前缀
if (arr[j].length === i) {
return arr[0].slice(0, i);
}
//同样的操作,用每个字符串的前缀作为键,存入对象中
obj[arr[j].slice(0, i + 1)] = true;
//obj[arr[j][i+1]] = true
}
//每轮内层循环结束后,检查对象中的键的个数
//如果键的个数大于1,说明有字符串的当前前缀与第一个字符串的当前前缀不同,
//返回最大公共前缀
if (Object.keys(obj).length > 1) {
return arr[0].slice(0, i);
}
//如果所有字符串的当前前缀都相同,则清空当前对象,进入下一轮前缀比对
obj = {}
}
//如果所有字符串都被比对完,所有字符串的前缀都相同,
//则返回第一个字符串,这就是最大公共前缀
return arr[0];
};
我想顺着这个思路,大家应该很快就能想到Set,没错,Set类型的数据的每一项也是唯一的,完全可以取代obj对象:
longestCommonPrefix(arr) {
if (arr == null || arr[0].length == 0) return "";
let obj = {}
let mySet = new Set();
for (let i = 0; i < arr[0].length; i++) {
// obj[arr[0].slice(0, i + 1)] = true;
mySet.add(arr[0].slice(0, i + 1));
for (let j = 1; j < arr.length; j++) {
if (arr[j].length === i) {
return arr[0].slice(0, i);
}
// obj[arr[j].slice(0, i + 1)] = true;
mySet.add(arr[j].slice(0, i + 1));
}
// if (Object.keys(obj).length > 1) {
// return arr[0].slice(0, i);
// }
if (mySet.size > 1) {
return arr[0].slice(0, i);
}
// obj = {}
mySet.clear();
}
return arr[0];
}
结语
上述内容是本人的突发奇想,不符合传统算法思想,利用js特性来实现功能,单纯就是提供一种实现方法,仅供娱乐。
这是本人的第一篇文章,非常粗糙,如果有朋友看到,还请见谅!