速通LeetCode hot100——(1~9 哈希,双指针,滑动窗口)

目录

哈希:

[1. 两数之和](#1. 两数之和)

[49. 字母异位词分组](#49. 字母异位词分组)

[128. 最长连续序列](#128. 最长连续序列)

双指针:

[283. 移动零](#283. 移动零)

[11. 盛最多水的容器](#11. 盛最多水的容器)

[15. 三数之和](#15. 三数之和)

[42. 接雨水](#42. 接雨水)

滑动窗口:

[3. 无重复字符的最长子串](#3. 无重复字符的最长子串)

[438. 找到字符串中所有字母异位词](#438. 找到字符串中所有字母异位词)


哈希:

1. 两数之和

也是很多人写的第一道题吧,学过哈希不难写出进阶条件,简简单单,

遍历数组的同时一边存,一边判断,找到返回。

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 哈希记录下标和值的存在,
        unordered_map<int, int> hash;
        for(int i = 0; i < nums.size(); ++i){
            if(hash.count(target - nums[i])){
                return {hash[target - nums[i]], i};
            }
            else{
                hash.emplace(nums[i], i);
            }
        }
        return {0, 0};
    }
};

49. 字母异位词分组

博主有的僵化了,hash表先存了下标,又因为最后返回要原本的string,又去copy了一份strs

,算了,懒得优化,理这个题了。官解方法二似乎是用统计的string,每个字母的出现次数去做哈希的key。不管了,知道数据特殊时可以从这里优化key就行

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        //排序肯定最爽,
        vector<string> tmp = strs;
        for(auto& str : tmp){
            sort(str.begin(), str.end());
        }
        //给它一个组id,
        int id = 0;
        unordered_map<string, int> hash;
        for(int i = 0; i < tmp.size(); ++i){
            if(hash.count(tmp[i])){
                continue;
            }
            else{
                hash[tmp[i]] = id++;
            }
        }
        vector<vector<string>> vvs_ret(id);
        for(int i = 0; i < strs.size(); ++i){
            int ret_id = hash[tmp[i]];
            vvs_ret[ret_id].push_back(strs[i]);
        }
        return vvs_ret;
    }
};

128. 最长连续序列

,博主没想到 if(hash.count(num - 1)){ continue; } 这一层,还没想到在set里去重后的去找,真是一直超时,麻了,看了题解才反应过来。

cpp 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        //对于连续的最长序列,找到起始最小的/末尾最大的就可以确定返回,
        //遍历数组的时候 去找nums[i] - 1是否存在,找到最小的去计算一下长度
        int ret = 0;
        unordered_set<int> hash(nums.begin(), nums.end());
        // num之后的数量
        auto f = [&](int num){
            int count = 0;
            while(hash.count(num + count)){
                count++;
            }
            return count;
        };
        for(auto num : hash){
            if(hash.count(num - 1)){ continue; }
            ret = max(ret, f(num));
            //优化
            if(ret * 2 >= nums.size()) return ret;
        }
        return ret;
    }
};

双指针:

283. 移动零

没啥好说的,基础题,再优化就是考虑特殊场景进行优化

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int l = 0, f = 0;
        for( ; f < nums.size(); ++f){
            if(nums[f] == 0) continue;
            nums[l] = nums[f];
            ++l;
        }
        for( ; l < nums.size(); ++l){
            nums[l] = 0;
        }
    }
};
11. 盛最多水的容器

这种关于水的,谁做过会忘记啊!

cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        //第一眼,前缀和,第二眼,不行,要宽,控制宽度,模拟一下就知道是双指针了
        int l = 0, r = height.size() - 1;
        int ret = 0;
        while(l < r){
            ret = max(ret, (r - l) * min(height[l], height[r]));
            if(height[l] < height[r]){
                ++l;
            }
            else{
                --r;
            }
        }
        return ret;
    }
};
15. 三数之和

这个方法就是我们常说的「双指针」,当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法------来自官方题解

不会降维(指O(N^3)->O(N^2)这样的降一重复杂度)不是什么奇怪的事,不会去重也不是什么奇怪的事,看得懂题解,记住诀窍就好。

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size() - 2; ++i){
            if(i != 0 && nums[i - 1] == nums[i]) continue;
            int aim = -nums[i];
            int l = i + 1, r = nums.size() - 1;
            while(l < r){
                int tmp = nums[l] + nums[r];
                if(tmp > aim){
                    --r;
                }
                else if(tmp < aim){
                    ++l;
                }
                else{
                    ret.push_back({nums[i], nums[l], nums[r]});
                    ++l;
                    while(l != 0 && nums[l - 1] == nums[l] && l < r) ++l;
                    --r;
                    while(r != 0 && nums[r] == nums[r + 1] && r > l) --r;
                }
            }
        }
        return ret;
    }
};
42. 接雨水

第一遍写的时候,没学过前缀和可能会没思路,有前缀和经验的,或者做过一遍就会发现,这个题完全是伪装成困难的简单题。,官方题解也很友好,不必看长篇文字,看动画就能理解。

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        //做过就很简单
        //前缀,后缀和
        int n = height.size();
        if(n < 3) return 0;
        vector<int> r(n, 0);
        for(int i = n - 2; i > 0; --i){
            r[i] = max(r[i + 1], height[i + 1]);
        }
        int l_max = 0;
        int ret = 0;
        for(int i = 1; i < n; ++i){
            int tmp = min(r[i], max(l_max, height[i - 1]));
            ret += tmp > height[i] ? tmp - height[i] : 0;
            l_max = max(l_max, height[i - 1]);
        }   
        return ret;
    }
};

滑动窗口:

3. 无重复字符的最长子串

滑动数组题目就那几种类型,练一练就会了。(不知道去哪找题?,找灵神呗)

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_set<char> hash;
        int ret = 0;
        int l = 0, r = 0;
        for( ; r < s.size(); ++r){
            if(hash.count(s[r])){
                ret = max(r - l, ret);
                while(l < r && hash.count(s[r])){
                    hash.erase(s[l]);
                    ++l;
                }
            }
            hash.emplace(s[r]);
        }
        ret = max(r - l, ret);
        return ret;
    }
};
438. 找到字符串中所有字母异位词

有定长滑动,有不定长滑动,都行,(这块儿知道了,c++大部分容器支持互相比较,还有c++11的安全静态数组array)

cpp 复制代码
//定长
class Solution {
    unordered_map<char, int> hash;
public:
    bool hashIs0(){
        for(auto [a, b] : hash){
            if(b > 0) return false;
        }
        return true;
    }
    // void print_(){
    //     for(auto [a, b] : hash){
    //         cout << '[' << a << ':' << b << ']' << "  ";
    //     }
    //     cout <<endl;
    // }
    vector<int> findAnagrams(string s, string p) {
        if(p.size() > s.size()) return {};
        //想到了
        for(char ch = 'a'; ch <= 'z'; ++ch){
            hash[ch] = 0;
        }
        for(auto ch : p){
            hash[ch]--;
        }
        int l = 0, r = 0;
        vector<int> ret;
        for(; r < p.size(); ++r){
            ++hash[s[r]];
        }
        while(r < s.size()){
            if(hashIs0()) ret.push_back(l);
            hash[s[l]]--;
            ++l;
            hash[s[r]]++;
            ++r;
        }
        if(hashIs0()) ret.push_back(l);
        return ret;
    }
};
相关推荐
2501_924952692 小时前
分布式缓存一致性
开发语言·c++·算法
hmbbcsm2 小时前
动手学习深度学习学习笔记(一)
笔记·学习
春水碧于天,画船听雨眠2 小时前
jQuery学习笔记
笔记·学习·jquery
炸膛坦客2 小时前
单片机/C/C++八股:(二十一)include <> 和 include ““ 的区别
c语言·c++
Yupureki2 小时前
《Linux系统编程》12.基础IO
linux·运维·c语言·开发语言·数据库·c++
Jordannnnnnnn2 小时前
追赶32名
c++
炸膛坦客2 小时前
单片机/C/C++八股:(十八)C/C++ 中 sizeof 和 strlen 的区别
c语言·c++
XiYang-DING2 小时前
【LeetCode】LCR 019. 验证回文串 II
算法·leetcode·职场和发展