LeetCode 面试150--滑动窗口-双指针

最近准备面试,我以前不愿意面对的

现在保持一颗本心,就是专注于算法思想,语言基础的磨炼;

不为速成,不急功近利的想要比赛,或者为了面试。

单纯的本心,体验算法带来的快乐,是一件非常了不起的事。

加油,持续输出~

战胜恐惧最好的方法,就是面对

一、滑动窗口

1. 最小覆盖子串

集成度越高的结构体(unordered_map)再使用上虽然方便,但遇到多次循环处理,处理速度不如用vector维护的可变数组;

把两组映射转换为一个数组,非常巧妙;

运行速度真的是见仁见电脑吗?我参考的1ms 的写法,甚至把他的源码,放我的LeetCode提交,我的最快也还是3ms。

(想到了飞驰人生2,虽然比不上专业赛车,只要你苦练技术,一定可以超越自己)

/*滑动窗口 O(1)
对于一个数组、字符串、链表 原串 s 目标串 t 最终结果 res
定义两个hash map: hs 负责记录滑动窗口,ht 负责目标串
定义i,j两个指针,i负责扩展,满足条件 cnt 计数器++
j负责缩圈 当满足条件,j--
*/
//模板
string minWindow(string s, string t) {
        unordered_map<char, int> hs, ht;
        for(auto a : t)
            ht[a]++;
        int cnt = 0;
        string res = "";
        for(int i=0, j=0; i < s.size(); i++)
        {
            hs[s[i]]++;
            if(hs[s[i]] <= ht[s[i]])//条件可根据实际发生变化
               cnt++;
            while(hs[s[j]] > ht[s[j]]) //缩圈
               hs[s[j++]]--;
            if(cnt == t.size() && (res == ""||res.size() > (i-j+1)))
            {//条件根据实际情况
               res = s.substr(j, i-j+1);
            }
        }
        return res;
}
string minWindow(string s, string t) {
    vector<int> ht(128, 0); //目标子串
    for (auto a : t)
      ht[a]++;
    int cnt = 0;
    int rlen = INT_MAX;               //最小覆盖子串的长度
    int len = t.size();               //目标子串长度
    int i = 0, j = 0, rj = 0, ri = 0; //左右指针,上一次最优解的左右指针
    for (; i < s.size(); i++) {
      if (ht[s[i]] > 0)
        cnt++;    //目标串中存在当前字符,覆盖子串的长度加1
      ht[s[i]]--; //每个字符都减1,如果目标字符都是0,则覆盖,
      //如果是-1 源串有重复的目标字符,缩小覆盖子串的长度
      if (cnt == len) {
        while (ht[s[j]] < 0) {
            ht[s[j]]++; //把多减掉加回来
            j++;        //指针往后移动
        }
        if(rlen > (i - j + 1)){
            //更新目标子串
            rlen = (i - j + 1);
            ri = i;
            rj = j;
        }
      }
    }
    if (rlen != INT_MAX)
      return s.substr(rj, ri - rj + 1);
    else
      return "";
  }

2 长度最小子数组

输入输出流的取消能快很多+一些特殊判断

auto optimize_cpp_stdio=[](){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    return 0;
}();
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int hs = 0;
        int nlen = nums.size();
        int len = nlen + 1;
        for(int i=0,j=0; i < nlen; i++)
        {
            hs+= nums[i];            
            while(hs-nums[j] >= target){
                hs=hs-nums[j]; 
                j++;
            } 
            if(hs >= target && len > i-j+1)
                len = i-j+1;
            if(len == 1)
                return 1;
        }
        if(len!=nlen+1)
            return len;
        else
            return 0;
    }
};

3 无重复字符的最长子串

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int> v(128,0);//保存子串出现的次数
        int len = s.length();
        int max_len = 0;
        int cnt = 0;
        for(int i=0, j=0; i < len; i++)
        {
            v[s[i]]++;
            cnt++;
            while (v[s[i]]>1 && j<i) {//子串出现重复,需要缩圈
                v[s[j]]--;
                j++;
                cnt--;
            }
            if(cnt > max_len)
            {
                max_len = cnt;//保存当前最长的子串范围
            }
        }
        
        return max_len;
    }
};

4. 串联所有单词子串

auto optimize_cpp_stdio=[](){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    return 0;
}();

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
  int wsize = words.size(), dlen = words[0].length();
      int wslen = wsize * dlen;
      int slen = s.size();
      if (slen == 0||wsize == 0 ||dlen == 0 || wslen > s.size()) 
        return vector<int>{};
      vector<int>res;
      unordered_map<string, int> mpWord;
      for(string word : words)
        mpWord[word]++;
      string sub = "";
      string subl = "";
      for(int wStart = 0; wStart < dlen; wStart++)
      {
        int wl = wStart, wr= wStart;
        int cnt = 0;
        unordered_map<string, int> winMap;
        while(wr + dlen <= slen){
          sub = s.substr(wr, dlen);
          wr+= dlen;
          if(mpWord.count(sub)==0){
            cnt = 0;
            wl = wr;
            winMap.clear();
          }
          else{
            winMap[sub]++;
            cnt++;
            while(winMap[sub] > mpWord[sub]){
              subl = s.substr(wl, dlen);
              winMap[subl]--;
              cnt--;
              wl += dlen;
            }
          }
          if(cnt == wsize) res.push_back(wl);
        }
      }
      return res;
    }
};

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值