3. 无重复字符的最长子串
「题目:」
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
「示例:」
输入: s = "abcabcbb",输出: 3 。
「解题思路:」
这种处理子串的问题,通常使用滑动窗口来解决:
使用双指针技巧,左指针维护滑动窗口的左边界,右指针维护滑动窗口的右边界。
不断移动右指针,利用哈希表判断当前元素是否重复出现,如果当前元素已经出现过,则通过哈希表查出该元素第一次出现的位置,并更新左指针的位置。
在窗口滑动的过程中,不断对比当前窗口的长度,从而获取到不重复子串的最大长度。
时间复杂度:O(n),空间复杂度:O(n)。
const lengthOfLongestSubstring = function(s) {
let start = 0;
let ans = 0;
const record = new Map();
for (let end = 0; end < s.length; end++) {
const char = s[end];
if (record.has(char) && record.get(char) >= start) {
start = record.get(char) + 1;
}
record.set(char, end);
ans = Math.max(ans, end - start + 1);
}
return ans;
};
567. 字符串的排列
「题目:」
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
s1 和 s2 仅包含小写字母。
「示例:」
输入:s1 = "ab" s2 = "eidbaooo",输出:true。
「解题思路:」
本道题也可以采用滑动窗口来解决:
由于滑动窗口的大小是固定的,所以移动右指针的过程中,左指针的位置也是已知的。
在窗口滑动的过程中,需要通过两个哈希表来判断字符串 s1 是否为当前窗口字符串的排列。
时间复杂度:O(nm),空间复杂度:O(n)。
const isMapEqual = (m1, m2) => {
if (m1.size !== m2.size) {
return false;
}
for (const [key, val] of m1) {
const val2 = m2.get(key);
if (val2 !== val || !m2.has(key)) {
return false;
}
}
return true;
}
const checkInclusion = function(s1, s2) {
const len1 = s1.length;
const len2 = s2.length;
if (len1 > len2) {
return false;
}
const record1 = new Map();
for (let i = 0; i < s1.length; i++) {
if (!record1.has(s1[i])) {
record1.set(s1[i], 0);
}
record1.set(s1[i], record1.get(s1[i]) + 1);
}
const record2 = new Map();
for (let i = 0; i < s1.length; i++) {
if (!record2.has(s2[i])) {
record2.set(s2[i], 0);
}
record2.set(s2[i], record2.get(s2[i]) + 1);
}
if (isMapEqual(record1, record2)) {
return true;
}
for (let i = len1; i < len2; i++) {
record2.set(s2[i], (record2.get(s2[i]) || 0) + 1);
record2.set(s2[i - len1], record2.get(s2[i - len1]) - 1);
if (record2.get(s2[i - len1]) === 0) {
record2.delete(s2[i - len1]);
}
if (isMapEqual(record1, record2)) {
return true;
}
}
return false;
};
由于 s1 和 s2 中仅包含小写字母,那么可以利用 Unicode 结合数组来记录字符的个数,并且由于小写字母的 Unicode 是升序的,所以维护两个字符串 Unicode 的数组也是升序的,那么只需要比较两个数组的序列化字符串,即可判断 s1 是否当前字符串的子排列:
const checkInclusion = function(s1, s2) {
const len1 = s1.length;
const len2 = s2.length;
if (len1 > len2) {
return false;
}
const record1 = Array(26).fill(0);
const record2 = Array(26).fill(0);
for (let i = 0; i < len1; i++) {
++record1[s1[i].charCodeAt() - 97];
++record2[s2[i].charCodeAt() - 97];
}
if (record1.toString() === record2.toString()) {
return true;
}
for (let i = len1; i < len2; i++) {
++record2[s2[i].charCodeAt() - 97];
--record2[s2[i - len1].charCodeAt() - 97];
if (record1.toString() === record2.toString()) {
return true;
}
}
return false;
}
写在最后
「感谢您能耐心地读到这里,如果本文对您有帮助,欢迎点赞、分享、或者关注下方的公众号哟。」
相关链接:
《3. 无重复字符的最长子串》 https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
《567. 字符串的排列》 https://leetcode-cn.com/problems/permutation-in-string/