开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
- 28.实现 strStr()
- 459.重复的字符串
- 字符串总结
- 双指针回顾
KMP算法
什么是KMP?
KMP算法是一种改进的字符串匹配算法
核心:利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
时间复杂度:O(m+n)
解决什么问题?
解决字符串匹配问题。
前后缀
字符串的前缀:不包含最后一个字符的所有以第一个字符开头的连续子字符串 字符串的后缀:不包含第一个字符的所有以最后一个字符结尾的连续子字符串
所以说,我们要求的实际上是,一个字符串里面它的最长相等前后缀。
感觉KMP算法一时半会有点难懂,文末的参考文章里面放了其他大佬的讲解。溜了,等过段时间再来更新KMP算法的解题讲解。
28.实现 strStr()
题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
例如:haystack = "mississippi", needle = "issip"; 返回 4
我的解法
思路:
- 遍历字符串 haystack 的每个字母,直到遇到字母和字符串 needle 的第一个字母相同
- 取得字符串 needle 的长度,设为 needLen
- haystack 从该字母处截取,长度为 needLen 。所取子串放到 temp 里面
- 对比子串 temp 和 字符串 needle是否相同。
var strStr = function (haystack, needle) {
// 当needle里面的字符比haystack还多时,肯定找不到匹配下标
if (haystack.length < needle.length) return -1;
// 先求得needle的长度
let needLen = needle.length;
// let haystack = Array.from(haystack);
for (let i = 0; i < haystack.length; i++) {
if (haystack[i] == needle[0]) {
let temp = haystack.slice(i, i + needLen)
// console.log(temp);
if (temp == needle) {
return i
} else {
continue
}
}
}
// 如果for循环过后还是找不到匹配的,就返回-1
return -1
};
卡神解法
本题是KMP 经典题目。
// 前缀表统一减一
var strStr = function (haystack, needle) {
if (needle.length === 0)
return 0;
const getNext = (needle) => {
let next = [];
let j = -1;
next.push(j);
for (let i = 1; i < needle.length; ++i) {
while (j >= 0 && needle[i] !== needle[j + 1])
j = next[j];
if (needle[i] === needle[j + 1])
j++;
next.push(j);
}
return next;
}
let next = getNext(needle);
let j = -1;
for (let i = 0; i < haystack.length; ++i) {
while (j >= 0 && haystack[i] !== needle[j + 1])
j = next[j];
if (haystack[i] === needle[j + 1])
j++;
if (j === needle.length - 1)
return (i - needle.length + 1);
}
return -1;
};
459.重复的字符串
题目链接:459. 重复的子字符串 - 力扣(LeetCode)
给定一个非空的字符串
s,检查是否可以通过由它的一个子串重复多次构成。例如:输入: s = "abab",输出: true。解释: 可由子串 "ab" 重复两次构成。
我的解法
思路:
- 从字符串 s 中截取某一段字母。比如一开始截取第一个字母。
- 重复一定的次数压入数组中。这个次数怎么得来的呢?比如 'abab' 中,当 part = 'a' 时 ,arr 中通过
push()不断压入'a' 。想要 arr 长度和 s 的长度相等,那么就得用字符串长度除以所截取的子串的长度,就能得到 arr = ['a' , 'a' , 'a' , 'a' ] 。 - 对比此数组转为字符串后和 s 是否相等。
var repeatedSubstringPattern = function(s) {
let len = s.length;
// 这个 i 是用来截取字符串的,而且要求子串,所以不能等于 len
for (let i = 1; i < len; i++) {
let part = s.slice(0, i); // 截取到的字母片段
let arr = [];
// 片段字母不断压入数组中,注意重复的次数
let times = len / part.length;
while (arr.length < times) {
arr.push(part);
}
// console.log(`字母片段是:${part},合成的数组是:${arr.join('')}`);
if (arr.join('') == s) {
return true
}
}
return false
};
卡神解法
var repeatedSubstringPattern = function (s) {
if (s.length === 0)
return false;
const getNext = (s) => {
let next = [];
let j = -1;
next.push(j);
for (let i = 1; i < s.length; ++i) {
while (j >= 0 && s[i] !== s[j + 1])
j = next[j];
if (s[i] === s[j + 1])
j++;
next.push(j);
}
return next;
}
let next = getNext(s);
if (next[next.length - 1] !== -1 && s.length % (s.length - (next[next.length - 1] + 1)) === 0)
return true;
return false;
};