滑动窗口
双指针中实现滑动窗口:核心就是右指针动时左指针不动,左指针动时,右指针不动。
举个例子,左右指针初始时都在起点,先让右指针动,此时左指针在初始位置不动,当满足搜索条件时,右指针不动,此时左右指针形成一个搜索区,而且搜索区中是符合搜索条件的,在让左指针向右移动,逐步减少搜索范围,当左指针移动到下一位置时,搜索区域就不符合搜索条件,那吗在让右指针向右移动,移动到符合搜索条件的位置,以此循环
视频:https://www.aliyundrive.com/s/yrivtJMo3on
题目
解题
可以查看上面的视频。 这道题要让我们在字符串中找到涵盖字符串t中的最小子串,而且字符串t是会有重复字符的,那就得对字符串t统计字符出现的次数,以及所需要的匹配字符串的个数。而这个最小子串那不就是说明字符串t中的字符都要出现,那就统计字符出现的次数,开始要t中的字符的出现的次数都为初始值1,当里面有重复值让其出现的次数+1,然后使用右指针去寻找符合规则的字符区域,每找到一个符合规则的字符,让其它所对应的出现的次数-1,同时让其所需要匹配的字符串个数-1,但是有可能会出现区域中出现重复字符,导致其出现次数为负值,此时就不能让其匹配的字符串个数-1。当其匹配字符串的个数为0时说明字符串t中的字符全找到啦,那就要停止右指针,让其左指针减少范围,让左指针向右移动,同时匹配左指针所指的字符是否符合字符串t中的字符,当其符合就将符合区域截取下来,保存左指针到右指针的距离。同时让其字符出现的次数+1,但是次数大于0才能让右指针动,因为可能区域内有的字符出现的次数为负值,而且要求最小子串,所以继续让左指针向右走,当左指针移动到下一位置,搜搜区域并没有t字符串中的所有字符时,让其右指针再次往右移动,再次寻找适合的搜索的的区域。而最后找到的肯定符合字符串t的最小子串
/*** @param {string} s* @param {string} t* @return {string}*/var minWindow = function(s, t) {let str ='';// 左指针let l = 0;// 字典 存放字符出现的次数 t中可能出现重复字符const map = new Map()for(let i = 0; i < t.length; i++){const curValue = t[i];map.set(curValue, map.get(curValue) ? map.get(curValue) + 1 : 1 )}//需要集齐的字符数量let count = t.length;// 符合规则字符串的长度let minLen = s.length;// 当map中有当前字符,就将当前字符的出现次数减一,当 <= 0说明该字符已找到// count-- 当count === 0 说明全部找齐,更新minlen的长度// 判断左指针的位置向右移动后,是否还符合条件, 符合条件左指针继续移动// r 为右指针for(let r = 0; r < s.length; r++) {const curValue = s[r];if(map.has(curValue)) {// 判断出现次数减减后是否大于0 小于零说明该字符多次出现map.set(curValue, map.get(curValue) - 1);if(map.get(curValue) >= 0){count--;}}// count 等于零时说明已经找齐所有字符while(count === 0) {// 是否小与最小字符串长度,if(r - l < minLen) {minLen = r - l ;str = s.slice(l, r + 1)}// 判断左指针当前指定的值是否为寻找的字符const lCurVal = s[l];if(map.has(lCurVal)) {map.set(lCurVal, map.get(lCurVal) + 1);if(map.get(lCurVal) > 0) count++}++l;}}return str};
牺牲有点空间,提高一点时间
/*** @param {string} s* @param {string} t* @return {string}*/var minWindow = function (s, t) {let l = 0;let r = 0;let res = '';const m = new Map();for (let i = 0; i < t.length; i++) {const c = t[i];m.set(c, m.has(c) ? m.get(c) + 1 : 1);}let needType = m.size;while (r < s.length) {const c = s[r];if (m.has(c)) {m.set(c, m.get(c) - 1);if (m.get(c) === 0) {needType -= 1;}}while (needType === 0) {const c2 = s[l];let newRes = s.slice(l, r + 1);if (!res || newRes.length < res.length) res = newRes;if (m.has(c2)) {// 更新表中需要出现的次数m.set(c2, m.get(c2) + 1);if (m.get(c2) === 1) needType += 1;}// 移动左指针l++;}// 移动右指针r++;}// 返回结果值return res;};
