题目
leetcode-438 找到字符串中所有字母异位词(未通过)
题目
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
代码
var findAnagrams = function(s, p) {
const sLen = s.length, pLen = p.length;
if (sLen < pLen) {
return [];
}
const ans = [];
// 26 字母表
const sCount = new Array(26).fill(0);
const pCount = new Array(26).fill(0);
for (let i = 0; i < pLen; ++i) {
++sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++pCount[p[i].charCodeAt() - 'a'.charCodeAt()];
}
// 第一个区间
if (sCount.toString() === pCount.toString()) {
ans.push(0);
}
for (let i = 0; i < sLen - pLen; ++i) {
// 这里的减去是为了 移除掉上一个区间留下的字符
--sCount[s[i].charCodeAt() - 'a'.charCodeAt()];
++sCount[s[i + pLen].charCodeAt() - 'a'.charCodeAt()];
console.log(sCount);
if (sCount.toString() === pCount.toString()) {
ans.push(i + 1);
}
}
return ans;
};
总结
这道题没有做出来,解题的思路 先把p字符串变成对应的pCount数组表,然后再跟进滑动窗口,每个窗口产生一个对应的数组表sCount与pCount做比较,每个存在的字符在数组表中表示为1。重点就在这个数组表
。
3. 无重复字符的最长子串(通过)
题目
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
自己写的代码
var lengthOfLongestSubstring = function(s) {
if(s.length < 1) {
return 0
}
let count = 0
for(let i=0;i<s.length;i++) {
let j = i+1, str = s[i]
while(true) {
if(str.includes(s[j])) {
break
}else {
if(j == s.length) {
break
}
str = str + s[j]
j++
}
}
if(count < str.length) {
count = str.length
}
}
console.log(count);
return count
};
使用了三层循环来完成。
看了别人的解题。
var lengthOfLongestSubstring = function(s) {
let arr = [];
let max = 0;
for (let i = 0; i < s.length; i ++) {
//如果之前存在,就删除,知道没有为止
if(arr.indexOf(s[i]) !== -1) {
arr.splice(0, arr.indexOf(s[i]) + 1);
}
//加入当前元素
arr.push(s[i]);
console.log(arr);
//取最大
max = Math.max(max, arr.length);
}
return max;
};
他这里只使用了 双层循环,一个值放进数组中,当遇到相同的就从头到相同的地方切掉。
总结
这道题感觉我自己的代码没有滑动窗口的味道。从别人的题解中看出一直向前走,而未回头。从前面的地方做删除。
76. 最小覆盖子串(未通过)
题目
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。
输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
代码
const minWindow = (s, t) => {
let minLen = s.length + 1;
let start = s.length; // 结果子串的起始位置
let map = {}; // 存储目标字符和对应的缺失个数
let missingType = 0; // 当前缺失的字符种类数
for (const c of t) { // t为baac的话,map为{a:2,b:1,c:1}
if (!map[c]) {
missingType++; // 需要找齐的种类数 +1
map[c] = 1;
} else {
map[c]++;
}
}
// 先右指针跑,跑到全部值都有了,就暂停,左指针移动。
let l = 0, r = 0; // 左右指针
for (; r < s.length; r++) { // 主旋律扩张窗口,超出s串就结束
let rightChar = s[r]; // 获取right指向的新字符
if (map[rightChar] !== undefined) map[rightChar]--; // 是目标字符,它的缺失个数-1
if (map[rightChar] == 0) missingType--; // 它的缺失个数新变为0,缺失的种类数就-1
while (missingType == 0) { // 当前窗口包含所有字符的前提下,尽量收缩窗口
if (r - l + 1 < minLen) { // 窗口宽度如果比minLen小,就更新minLen
minLen = r - l + 1; // 表示当前窗口有多大
start = l; // 更新最小窗口的起点 这start还是跟在l后面的
}
let leftChar = s[l]; // 左指针要右移,左指针指向的字符要被丢弃
console.log(leftChar);
if (map[leftChar] !== undefined) map[leftChar]++; // 被舍弃的是目标字符,缺失个数+1
if (map[leftChar] > 0) missingType++; // 如果缺失个数新变为>0,缺失的种类+1
l++; // 左指针要右移 收缩窗口
}
}
if (start == s.length) return "";
return s.substring(start, start + minLen); // 根据起点和minLen截取子串
};
总结
在这里看到双指针 其实可以说是3指针 先左右 后面还跟这一个start,这里的关键有两点一个是使用了对象的的key来保存了某个字母出现的次数,第二个就是missingType,用来表示某个字符串是匹配完成。
剑指 Offer 59 - I. 滑动窗口的最大值(通过)
题目
给定一个数组 nums
和滑动窗口的大小 k
,请找出所有滑动窗口里的最大值。
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
代码
var maxSlidingWindow = function(nums, k) {
if(nums.length < 1 || !k) {
return []
}
let left = 0, right = k, res = []
for(;right<=nums.length;) {
const arr = nums.slice(left,right)
res.push(Math.max(...arr))
right++
left++
}
return res
};
总结
这道题的难度系数不是很大,使用了一个双指针,还有数组切片。
209. 长度最小的子数组
题目
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组。
代码
自己
var minSubArrayLen = function(target, nums) {
let left = 0, right = 0, count = 0, res = Infinity
for(;right<nums.length;) {
while(count < target) {
count = count + nums[right]
right++
}
while(count >= target) {
if((right - left) < res ) {
res = right - left
}
count = count - nums[left]
left++
}
}
if(res == Infinity) {
return 0
}
return res
};
题解代码
var minSubArrayLen = function (target, nums) {
let left = 0,
right = 0,
count = 0,
res = Infinity;
for (; right < nums.length; ) {
count = count + nums[right];
console.log(count);
while (count >= target) {
if (right - left + 1 < res) {
res = right - left + 1;
}
count = count - nums[left];
left++;
}
right++;
}
if (res == Infinity) {
return 0;
}
return res;
};
总结
题解的和我的差不多只是没有优化而已,这种就是双指针。
最后大总结
从这些题目中,学习到了技巧:
- 当判断字符串中的某些字符,可以使用对象来获取判断是不是有相同的。
- 双指针形式,但是需要知道什么时候停止。
- 就是可以把字符转成数字 使用charCodeAt函数进行转换。其实使用前面两种结合也能实现这个功能。