HOT100与剑指Offer


前言

一个本硕双非的小菜鸡,备战24年秋招,计划刷完hot100和剑指Offer的刷题计划,加油!
根据要求,每一道题都要写出两种以上的解题技巧。

一、76. 最小覆盖子串(HOT100)

76. 最小覆盖子串
Note:滑动窗口
过程如下:
1、遍历t字符串,用ht哈希表记录t字符串各个字符出现的次数。
2、定义两个指针j和i,j指针用于收缩窗口,i指针用于延伸窗口,则区间[j,i]表示当前滑动窗口。首先让i和j指针都指向字符串s开头,然后枚举整个字符串s ,枚举过程中,不断增加i使滑动窗口增大,相当于向右扩展滑动窗口。
3、每次向右扩展滑动窗口一步,将s[i]加入滑动窗口中,而新加入了s[i],相当于滑动窗口维护的字符数加一,即hs[s[i]]++。
4、对于新加入的字符s[i],如果hs[s[i]] <= ht[s[i]],说明当前新加入的字符s[i]是必需的,且还未到达字符串t所要求的数量。我们还需要事先定义一个cnt变量, cnt维护的是s字符串[j,i]区间中满足t字符串的元素的个数,记录相对应字符的总数。新加入的字符s[i]必需,则cnt++。
5、我们向右扩展滑动窗口的同时也不能忘记收缩滑动窗口。因此当hs[s[j]] > ht[s[j]时,说明hs哈希表中s[j]的数量多于ht哈希表中s[j]的数量,此时我们就需要向右收缩滑动窗口,j++并使hs[s[j]]–,即hs[s[j ++ ]] --。
6、当cnt == t.size时,说明此时滑动窗口包含符串 t 的全部字符。我们重复上述过程找到最小窗口即为答案。

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char, int> hs, ht;
        for (auto c : t) ht[c]++;
        string res;
        int nums = 0;

        for (int i = 0, j = 0; i < s.size(); i++) {
            hs[s[i]]++;
            if (hs[s[i]] <= ht[s[i]]) nums++;

            while (hs[s[j]] > ht[s[j]]) hs[s[j++]]--;

            if (nums == t.size()) {
                if (res.empty() || i - j + 1 < res.size())
                    res = s.substr(j, i - j + 1);
            }
        }
        return res;
    }
};

Note:

  1. 使用滑动窗口,i为左指针,j为右指针。、
  2. 用了两个数组,一个数组need[128]表示所需字符及个数,一个数组have[128]动态维护窗口中的字符及的个数。
  3. 额外使用一个变量need_num,记录当前所需字符数量,当数量为0即满足需求。

思路:

  1. j指针不断右移,并且将当前字符填充到数组have,如果当前字符为所需字符,且have数量<need,则need_num–
  2. 当need_num=0时,此时j为可行窗右边界,因此,进行下一步,将i移动到左边界。
  3. i指针不停右移,并且have数量-1,当have[s[i]] < need[s[i]]时说明这个数的去除使得需求不满足,则i为左边界。 此时便可以计算子字符串长度了
class Solution {
    public:
        string minWindow(string s, string t) {

        //定义两个数组,记录所需字符,和已有字符
        int need[128] ={0}; //ASCII表总长128
        int have[128] ={0};
        int need_num=0;//计算还需要多少个字符

        for (char i:t) //记录所需字符数量
        { 
            need[i]++;  
            need_num++; 
        }

        //ij双指针,子字符串长度,子字符串开始位置
        int i = 0, j = 0, subString_len = INT_MAX, subString_start = 0;

        for(j=0; j < s.size();j++)//j指针遍历
        {
            have[s[j]]++;//填充
            if(need[s[j]] && (have[s[j]]<=need[s[j]])) //如果在需求里,并且没有超过需求的情况下
                need_num--;
            
            if(need_num==0)//满足所有需求,则此时j指针指向窗口右侧
            {
                for(;i<=j;i++)//i 不停右移,寻找左边界
                {
                    have[s[i]]--;
                    //如果去掉这个数使得已有的数比需要的数少,则说明此时i为左边界
                    if(need[s[i]] && (have[s[i]] < need[s[i]]))
                    {
                        int len=j-i+1;
                        if(len < subString_len)//如果现有长度小于默认长度
                        {
                            subString_start=i;//记录起点
                            subString_len=len;//记录长度
                        }
                        i++;//i前进一格
                        need_num++;//需求数量+1
                        break;
                    }
                }
            }  
        }

        if(subString_len==INT_MAX)
            return "";
        return s.substr(subString_start,subString_len);
    }
};

二、21. 调整数组顺序使奇数位于偶数前面(剑指Offer)

调整数组顺序使奇数位于偶数前面

Note:简单思路。设置两个头尾指针维护。往中间扫描。扫描时保证第一个指针前面的数都是奇数,第二个指针后面的数都是偶数。

class Solution {
public:
    void reOrderArray(vector<int> &array) {
         int size = array.size();
         if (size <= 1) return;
         
         int leftIndex = 0;
         int rightIndex = size - 1;
         
         while (leftIndex != rightIndex) {
            if ((array[leftIndex] % 2 == 0) && (array[rightIndex] % 2 == 1))
                swap(array[leftIndex], array[rightIndex]);
            else if (array[leftIndex] % 2 == 1)
                leftIndex++;
            else
                rightIndex--;
         }
         return;
    }
};

Note:申请一个新空间,然后遍历两遍挨个往里塞。(offer消失术)

class Solution {
public:
    void reOrderArray(vector<int>& array) {
        vector<int> a;

        for (int x : array) {
            if (x % 2)
                a.push_back(x);
        }
        
        for (int x : array) {
            if (x % 2 == 0)
                a.push_back(x);
        }
        array = a;
    }
};

总结

祝大家都能学有所成,找到一份好工作!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力找工作的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值