Compare commits
3 Commits
1d8c16c31b
...
07a3353880
Author | SHA1 | Date | |
---|---|---|---|
07a3353880 | |||
17aed86c56 | |||
371b5ede81 |
60
top-interview-leetcode150/double-point/125验证回文字符串.js
Normal file
60
top-interview-leetcode150/double-point/125验证回文字符串.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/valid-palindrome/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} s
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isPalindrome = function (s) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
把符合要求的字符存入数组中,之后判断反转的数组和原数组是否一致,如果一致就是回文
|
||||||
|
*/
|
||||||
|
function f1(s) {
|
||||||
|
// 创建一个新的数组,用来存储有效字符(字母和数字)
|
||||||
|
const filteredChars = [];
|
||||||
|
|
||||||
|
// 遍历原字符串,将符合要求的字符存入新数组并转为小写
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
const char = s[i];
|
||||||
|
if (/[a-zA-Z0-9]/.test(char)) {
|
||||||
|
filteredChars.push(char.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将新数组转换为字符串,并与反转后的字符串比较
|
||||||
|
const reversedStr = filteredChars.slice().reverse().join('');
|
||||||
|
return filteredChars.join('') === reversedStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用双指针来判断是否符合要求,首先创建左右两个指针,判断当前字符是不是有效字符,如果不是就跳过,然后比较s[left] 和 s[right]
|
||||||
|
如果不相等直接返回false,如果循环遍历完毕都没问题,那么就是一个回文字符串,
|
||||||
|
思考:奇偶会影响判断吗?
|
||||||
|
*/
|
||||||
|
function f2(s) {
|
||||||
|
let left = 0;
|
||||||
|
let right = s.length - 1;
|
||||||
|
|
||||||
|
while (left < right) {
|
||||||
|
// 跳过非字母数字字符
|
||||||
|
if (!(/[a-zA-Z0-9]/.test(s[left]))) {
|
||||||
|
left++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(/[a-zA-Z0-9]/.test(s[right]))) {
|
||||||
|
right--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比较字符是否相等,忽略大小写
|
||||||
|
if (s[left].toLowerCase() !== s[right].toLowerCase()) {
|
||||||
|
return false; // 如果不相等,返回false
|
||||||
|
}
|
||||||
|
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // 如果完全匹配,返回true
|
||||||
|
}
|
39
top-interview-leetcode150/double-point/392判断子序列.js
Normal file
39
top-interview-leetcode150/double-point/392判断子序列.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/valid-palindrome/description/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} s
|
||||||
|
* @param {string} t
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isSubsequence = function (s, t) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
直接遍历,直接遍历t 检查当前s的第一个字符是否在遍历的过程中找到了,如果找到了,就指向s的第二个字符,继续找,找到全部找到 返回true
|
||||||
|
*/
|
||||||
|
function f1(s, t) {
|
||||||
|
if (s === t) return true;
|
||||||
|
let i = 0; // 指向s中要查找的字符
|
||||||
|
for (const char of t) {
|
||||||
|
if (char === s[i]) i++;
|
||||||
|
if (i === s.length) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用传统for提高效率
|
||||||
|
*/
|
||||||
|
function f2(s, t) {
|
||||||
|
if (s === t) return true;
|
||||||
|
let i = 0; // 指向s中要查找的字符
|
||||||
|
let j = 0; // 指向t中当前遍历的字符
|
||||||
|
for(let j = 0;j<t.length,t++) {
|
||||||
|
|
||||||
|
}
|
||||||
|
for (const char of t) {
|
||||||
|
if (char === s[i]) i++;
|
||||||
|
if (i === s.length) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
*https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} haystack
|
||||||
|
* @param {string} needle
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const strStr = function (haystack, needle) {
|
||||||
|
// return haystack.indexOf(needle); // 直接使用数组api
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
暴力解法,暴力解法思路非常简单,needle和haystack所有和needle长度一致的子串,如果匹配到相同的就返回,如果没有匹配到就返回-1
|
||||||
|
*/
|
||||||
|
function f1(haystack, needle) {
|
||||||
|
// 如果要查找的子串比字符串还长,直接返回
|
||||||
|
if (haystack.length < needle.length) return -1;
|
||||||
|
const lastIndex = haystack.length - needle.length; // haystack中最后一个子串的起始下标
|
||||||
|
for (let i = 0; i <= lastIndex; i++) {
|
||||||
|
let match = true;
|
||||||
|
for (let j = 0; j < needle.length; j++) {
|
||||||
|
if (haystack[i + j] !== needle[j]) {
|
||||||
|
// 当前位置的子串不符合要求,直接结束循环
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1; // 如果不匹配直接返回-1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
使用kmp来快速找出匹配的子串
|
||||||
|
*/
|
||||||
|
const kmpSearch = function (haystack, needle) {
|
||||||
|
const n = haystack.length;
|
||||||
|
const m = needle.length;
|
||||||
|
|
||||||
|
// 如果模式字符串为空,直接返回0
|
||||||
|
if (m === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建部分匹配表 (pi数组),用于记录模式串的匹配信息
|
||||||
|
const pi = new Array(m).fill(0);
|
||||||
|
|
||||||
|
// 计算pi数组
|
||||||
|
for (let i = 1, j = 0; i < m; i++) {
|
||||||
|
// 如果当前字符不匹配,则回溯到之前匹配的部分
|
||||||
|
while (j > 0 && needle[i] !== needle[j]) {
|
||||||
|
j = pi[j - 1]; // 回溯到上一个可能的匹配位置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前字符匹配,增加匹配长度
|
||||||
|
if (needle[i] === needle[j]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新pi数组
|
||||||
|
pi[i] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始搜索主字符串haystack
|
||||||
|
for (let i = 0, j = 0; i < n; i++) {
|
||||||
|
// 如果当前字符不匹配,则回溯
|
||||||
|
while (j > 0 && haystack[i] !== needle[j]) {
|
||||||
|
j = pi[j - 1]; // 回溯到上一个可能的匹配位置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果匹配成功,继续检查下一个字符
|
||||||
|
if (haystack[i] === needle[j]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果完整匹配模式串,则返回匹配的起始位置
|
||||||
|
if (j === m) {
|
||||||
|
return i - m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有匹配成功,返回-1
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
使用kmp,上面的写法是leetcode官方提供的,我按照自己的理解也写了下面这部分实现
|
||||||
|
*/
|
||||||
|
function f2(haystack, needle) {
|
||||||
|
const n = haystack.length; // 匹配串的长度
|
||||||
|
const m = needle.length; // 模式串的长度
|
||||||
|
|
||||||
|
// 1. 如果想使用kmp来快速跳过无用的遍历,就需要计算出模式串needle的next数组
|
||||||
|
const next = new Array(m).fill(0); // 初始化所有位置的前缀值为0(值初始化第一个位置也行)
|
||||||
|
for (let i = 1, j = 0; i < m; i++) { // i指向后缀的最后一个字符,j指向前缀的最后一个字符,按照kmp对前缀的定义,i初始化为1,j初始化为0
|
||||||
|
// 如果不相等,表示i指向的这个后缀最后一个字符和j指向前缀的最后一个字符不相等,这个时候我们需要找next[j-1]这个位置的字符
|
||||||
|
// 是否等于i指向的这个字符,以abaabaf为例,假设现在j指向abaa,i指向abaf,由于j和i指向的字符不相等,所以按照要求j应该移动
|
||||||
|
// next[j-1]的位置,j-1指向的是aba,next[j-1]表示的就是最大公共前后缀的长度那就是前缀”a“和后缀”a“长度为1,所以j指向了1,
|
||||||
|
// j=1时 指向的b并不等于f,所以还要继续把j移动到当前位置的next[j-1],所以这是一个循环的过程,并且要保证j>0,不然就会出现越界错误
|
||||||
|
// 上面的描述可能有点模糊可能体现不出为什么需要把j移动到next[j-1]的位置,
|
||||||
|
// abaabaf j = 3, i = 6, 前缀abaa 后缀abaf,显然不相等 所以后缀不可能包含aba了,只能aba里面的最大工作前后缀
|
||||||
|
// abaabaf j = 1, i = 6, 前缀ab,后缀af,显然不相等,继续往前找
|
||||||
|
while (j > 0 && needle[i] !== needle[j]) {
|
||||||
|
j = next[j - 1];
|
||||||
|
}
|
||||||
|
if (needle[i] === needle[j]) { // 如果相等,表示最大相同前缀需要往后移动一位
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
// 把当前j表示的就是最大前后缀长度
|
||||||
|
next[i] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 经过上面的计算,我们获得了一个模式串的next数组,现在我们就可以通过这个数组快速匹配了
|
||||||
|
for (let i = 0, j = 0; i < n; i++) {
|
||||||
|
// 如果当前字符不匹配,则回溯
|
||||||
|
while (j > 0 && haystack[i] !== needle[j]) {
|
||||||
|
j = next[j - 1]; // 回溯到上一个可能的匹配位置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果匹配成功,继续检查下一个字符
|
||||||
|
if (haystack[i] === needle[j]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果完整匹配模式串,则返回匹配的起始位置
|
||||||
|
if (j === m) {
|
||||||
|
return i - m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // 没有匹配到
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user