【面试HOT100】哈希双指针滑动窗口

news2024/11/19 11:29:20

系列综述:
💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于LeetCodeHot100进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
🌈【C++】秋招&实习面经汇总篇


文章目录

      • 基本算法
      • 哈希篇
        • 1. 两数之和
        • 49. 字母异位词分组
        • 128. 最长连续序列
      • 双指针篇
        • 283. 移动零
        • 11. 盛最多水的容器
        • 15. 三数之和
        • 42. 接雨水
      • 滑动窗口篇
        • 3. 无重复字符的最长子串
        • 438. 找到字符串中所有字母异位词


😊点此到文末惊喜↩︎

基本算法

  1. 排序
  2. set去重
  3. 哈希:数组全部扔入unordered_map可通过O(1)时间进行查找

哈希篇

1. 两数之和
  1. 问题
    • 给定一个整数数组 nums 和一个整数目标值 target
    • 在该数组中找出和为目标值 target 的那 两个 整数,并返回它们的数组下标。
  2. 思路
    • 暴力方法
    • 两次遍历
      • 第一次利用数组初始化哈希表
      • 第二次寻找非自身节点的目标结点
    • 单次遍历
      • 拿起一个看看和口袋中是否有一样的,没有则放入口袋
vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int, int> umap;	// 哈希表:存放数组中元素的位置和下标
    vector<int> res(2,-1);	
    for (int i = 0; i < nums.size(); i++) {
    	// 若含有目标元素,则赋值并结束循环
        if (umap.count(target-nums[i]) > 0) { // *判断是否含有元素
            res[0]=a[target-nums[i]];
            res[1]=i;
            break;
        }
        // 没有则记录
        umap[nums[i]]=i;	// *map的插入:key为数组元素,value为数组下标
    }
    return res;
};
  1. 总结
    • unordered_map比map更加节省空间
    • 使用if (umap.count(target_key) > 0),判断目标元素是否存在
49. 字母异位词分组
  1. 问题
    • 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
    • 给你一个字符串数组,请你将 字母异位词 组合在一起
  2. 思路
    • 简化:key是唯一性标识,value是任意类型的目标
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>> res;
        unordered_map <string,vector<string> > m;
        for(const string& s : strs) {
            string t = s;	// 利用字符串进行比较
            sort(t.begin(),t.end());
            m[t].push_back(s);  
        }
        for(auto& n : m) 
            res.push_back(n.second);
        return res;
    }
};
128. 最长连续序列
  1. 问题
    • 给定一个未排序的整数数组 nums
    • 找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
    • 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
  2. 思路
    • 通过数组初始化unordered_set,方便O(1)时间的查找
    • 去重优化:最长子序列一定是从最小的开始的,所有若n-1存在则直接跳过
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int res = 0;
        unordered_set<int> s(nums.begin(), nums.end());
        for(auto &n : s) {
        	// 健壮性检查:去重
            if(s.count(n-1)) continue; 
            // 初始化、算法、收尾
            int cnt = 0;
            while(s.count(n++)) ++cnt;
            res = max(res, cnt);
        }
        return res;
    }
};

双指针篇

283. 移动零
  1. 问题
    • 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾
    • 同时保持非零元素的相对顺序。
  2. 思路
    • 快慢指针 + 交换
void moveZeroes(vector<int>& nums) {
   int slow = 0, fast = 0;
    while (fast < nums.size()) {
        if (nums[fast] != 0) {
            swap(nums[slow], nums[fast]);
            slow++;
        }
        ++fast;
    }
}
11. 盛最多水的容器
  1. 问题
    • 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i])
    • 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水,返回容器可以储存的最大水量。
  2. 思路
    • 边界双指针:左右边界向中间慢慢收缩
int maxArea(vector<int>& height) {
     int left = 0, right = height.size() - 1
     int res = 0;
     while(left < right) {
         res = height[left] < height[right] ? 
             max(res, (right - left) * height[right++]): 
             max(res, (right  - left) * height[right--]); 
     }
     return res;
 }
  1. 待定思路
    • 左边向中间找更高,记录最值,右边向中间找更高,记录最值。
15. 三数之和
  1. 问题
    • 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。
    • 返回所有和为 0 且不重复的三元组。
    • 答案中不可以包含重复的三元组。
  2. 思路
    • 排序 + 分类讨论 + 去重在这里插入图片描述
vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>> result;
    sort(nums.begin(), nums.end()); // 排序:从小到大
    // 找出a + b + c = 0
    // a = nums[i], b = nums[left], c = nums[right]
    for (int i = 0; i < nums.size(); i++) {
        // 健壮性检查
        if (nums[i] > 0) return result;	// 排序若首元素已大于零,则不可能凑出结果
        if (i > 0 && nums[i] == nums[i - 1])// i的去重:i和已使用过的i-1比较,才是三元组间的去重
        	continue;
        // 初始化
        int left = i + 1;
        int right = nums.size() - 1;
        // 算法部分
        while (left < right) {
        	// 情况分类讨论
            if (nums[i] + nums[left] + nums[right] > 0) right--;
            else if (nums[i] + nums[left] + nums[right] < 0) left++;
            else {
                // key:注意如何进行vector的直接构造压入
                result.push_back(vector<int>{nums[i], nums[left], nums[right]});
                // 对left和right的去重
                while (left < right && nums[right] == nums[right - 1]) right--;
                while (left < right && nums[left] == nums[left + 1]) left++;
                // 找到答案时,双指针同时收缩
                right--;
                left++;   
            }
        }
    }
    return result;
}
42. 接雨水
  1. 问题
    • 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图
    • 计算按此排列的柱子,下雨之后能接多少雨水。
  2. 思路
    • 分类讨论:更大、更小、相等
      在这里插入图片描述
// 接雨水
int trap(vector<int>& height) {
    if (height.size() <= 2) return 0; // 可以不加
    stack<int> st; // 存着下标,计算的时候用下标对应的柱子高度
    st.push(0);
    int sum = 0;
    for (int i = 1; i < height.size(); i++) {
        if (height[i] < height[st.top()]) {     // 情况一
            st.push(i);
        } if (height[i] == height[st.top()]) {  // 情况二
            st.pop(); // 其实这一句可以不加,效果是一样的,但处理相同的情况的思路却变了。
            st.push(i);
        } else {      
            // 将i之前的比i小的全部凹槽计算水量
            while (!st.empty() && height[i] > height[st.top()]) { // 注意这里是while
                int mid = st.top();
                st.pop();
                if (!st.empty()) {  
                    int h = min(height[st.top()], height[i]) - height[mid];
                    int width = i - st.top() - 1; 
                    sum += h * w;
                }
            }
            st.push(i);
        }
    }
    return sum;
}
// 优化
// 接雨水
int trap(vector<int>& height) {
    if (height.size() <= 2) return 0; // 可以不加
    stack<int> st; // 存着下标,计算的时候用下标对应的柱子高度
    st.push(0);
    int sum = 0;
    for (int right = 1; right < height.size(); right++) {
        // 将前面小的全部出栈:计算right前的比height[right]的全部凹槽计算水量
        while (!st.empty() && height[right] > height[st.top()]) { 
            int mid = st.top();
            st.pop();
            if (!st.empty()) {  
                // st.top()为left的下标,即左右两柱-底部高度为水槽高度
                int left = st.top();
                int depth = min(height[left], height[right]) - height[mid];
                int width = right - left - 1; 
                sum += depth * width;
            }
        }
        st.push(right);
    }
    return sum;
}

滑动窗口篇

解决的问题:
给定一个线性表(字符串、数组等),一次遍历求满足指定条件的连续子部分

3. 无重复字符的最长子串
  1. 问题
    • 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
  2. 思路
    • 滑动窗口
int lengthOfLongestSubstring(string s) {
    const int N = s.size();
    if (N < 2) return N;

    int res = 0;
    unordered_map<char, int> umap;
    umap[s[0]] = 0;
    int slow = 0, fast = 1;
    while (fast < N) {
        // 缩小窗口:必须保证重复字符在滑动窗口内,因为过去的字符仍然在窗口内
        if (umap.count(s[fast]) > 0 && slow <= umap[s[fast]]) // 后半段判断的含义?
            slow = umap[s[fast]] + 1;
        // 扩大窗口
        umap[s[fast]] = fast;
        ++fast;
        res = max(fast-slow, res);
    }
    return res;

}
438. 找到字符串中所有字母异位词
  1. 问题
    • 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。
    • 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
  2. 思路
    • 快慢指针 + 交换
// 返回字符串 s 中包含字符串 t 的全部字符的最小窗口
string SlideWindow(string s, string t) {
	// need记录子串情况,window记录合适窗口
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;
	
    int left = 0, right = 0;
    // 记录最小覆盖子串的起始索引及长度
    int start = 0, len = INT_MAX;
    int valid = 0;
    while (right < s.size()) {
        char c = s[right];	// c 是将移入窗口的字符
        right++;			// 右移窗口
        // 进行窗口内数据的一系列更新
        if (need.count(c)) {
            window[c]++;
            if (window[c] == need[c])
                valid++;
        }
        while (valid == need.size()) {	// TODO:收缩条件
	        // TODO:更新结果记录
            if (right - left < len) {	
                start = left;// 更新起始值
                len = right - left;// 最小长度
            }
            // 收缩窗口
            char d = s[left];
            left++;
 			// TODO:收缩处理
            if (need.count(d)) {
                if (window[d] == need[d])
                    valid--;
                window[d]--;
            }                    
        }
    }
    // 返回最小覆盖子串
    return len == INT_MAX ?
        "" : s.substr(start, len);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建vue3工程

一、新建工程目录E:\vue\projectCode\npm-demo用Visual Studio Code 打开目录 二、点击新建文件夹按钮&#xff0c;新建vue3-01-core文件夹 三、右键vue3-01-core文件夹点击在集成终端中打开 四、初始化项目&#xff0c;输入npm init 一直敲回车直到创建成功如下图 npm init 五…

The directory ‘*‘ or its parent directory is not owned by the current user

python安装编译时出现如下错误 The directory /home/admin/.cache/pip/http or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may …

【办公软件】案例:电路中计算出的电阻值为5欧,怎么通过Excel匹配到仓库里最接近的电阻值?

在实际工作中&#xff0c;比如我们计算出一个电阻值为46欧&#xff0c;那么我们的库里到底是有哪个电阻值最接近呢&#xff1f;可能有一些有经验的工程师会说当然是47欧呀。 但是如果我们计算出来的是80.2欧呢&#xff1f;是不是得去查一下表格看看到底哪个最接近&#xff0c;…

PyTorch入门之【tensor】

目录 tensor的创建tensor的相关信息tensor的运算 tensor的创建 1.手动创建 import torch test1torch.tensor([1,2,3])#一维时为向量 test2torch.tensor([[1,2,3]])#二维时为矩阵 test3torch.tensor([[[1,2,3]]])#三维及以上统称为tensor print(test1) print(test2) print(tes…

C++ 类和对象篇(四) 构造函数

目录 一、概念 1. 构造函数是什么&#xff1f; 2. 为什么C要引入构造函数&#xff1f; 3. 怎么用构造函数&#xff1f; 3.1 创建构造函数 3.2 调用构造函数 二、构造函数的特性 三、构造函数对成员变量初始化 0. 对构造函数和成员变量分类 1. 带参构造函数对成员变量初始化 2. …

云存储解决方案-阿里云OSS

1. 阿里云OSS简介 阿里云对象存储服务&#xff08;Object Storage Service&#xff0c;简称OSS&#xff09;为用户提供基于网络的数据存取服务。使用OSS&#xff0c;用户可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种非结构化数据文件。 阿里云OSS将数据…

练[BJDCTF2020]Easy MD5

[BJDCTF2020]Easy MD5 文章目录 [BJDCTF2020]Easy MD5掌握知识解题思路关键paylaod 掌握知识 ​ 强等于和弱等于的MD5绕过&#xff0c;数据库查询的MD5加密绕过&#xff0c;代码审计 解题思路 打开题目链接&#xff0c;发现是一个post提交框&#xff0c;提交完了也就是url发…

自然语言处理 | WordNet

WordNet是词汇数据库,即英语词典,专为自然语言处理而设计。 Synset是一种特殊的简单接口,存在于 NLTK 中, 用于在 WordNet 中查找单词。同义词集实例是表达相同概念的同义词的分组。有些单词只有一个同义词集,有些则有多个。

【kubernetes】使用helm部署redis

1 什么是helm 在学习使用k8s进行应用的部署时&#xff0c;或者从github上下载一些组件进行部署时&#xff0c;通常是直接用yaml的方式部署&#xff0c;用这种方式部署时&#xff0c;有个比较大的问题是&#xff0c;当参数需要调整时&#xff0c;就需要阅读整个yaml文件&#x…

UG\NX CAM二次开发 加工模块获取 UF _ask_application_module

文章作者:代工 来源网站:NX CAM二次开发专栏 简介: UG\NX CAM二次开发 加工模块获取 UF _ask_application_module 代码: void MyClass::do_it() { // TODO: add your code here // 获取NX当前所在的模块 int module_id = 0; // UF_ask_application_module(&…

Android改造CardView为圆形View,Kotlin

Android改造CardView为圆形View&#xff0c;Kotlin 可以利用androidx.cardview.widget.CardView的cardCornerRadius特性&#xff0c;将CardView改造成一个圆形的View&#xff0c;技术实现的关键首先设定CardView为一个宽高相等的View&#xff08;正方形&#xff09;&#xff0c…

在PHP8中使用instanceof操作符检测对象类型-PHP8知识详解

在PHP8中使用instanceof操作符可以检测当前对象属于哪个类。语法格式如下&#xff1a; objectName instanceof classname下面我们用一个实例来讲解使用instanceof操作符检测对象类型。 本实例将将创建3个类&#xff0c;其中有两个类是父类和子类的关系&#xff0c;然后实例化…

时序预测 | MATLAB实现EMD-iCHOA+GRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测

时序预测 | MATLAB实现EMD-iCHOAGRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测 目录 时序预测 | MATLAB实现EMD-iCHOAGRU基于经验模态分解-改进黑猩猩算法优化门控循环单元的时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 EMD-iCHOAGR…

第一百六十四回 如何实现NumberPicker

文章目录 1.概念介绍2.使用方法2.1 NumberPicker2.2 CupertinoPicker 3.示例代码4.内容总结 我们在上一章回中介绍了"如何在任意位置显示PopupMenu"相关的内容&#xff0c;本章回中将介绍如何实现NumberPicker.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.概…

【知识点随笔分析 | 第七篇】什么是Cookie、Session、Token

前言&#xff1a; 当今互联网世界的发展让网站和应用程序扮演着重要的角色。为了实现用户身份验证、数据传输和用户状态管理等功能&#xff0c;开发人员常常使用一些关键技术来确保安全性和持久性。而在这些技术中&#xff0c;Cookie、Session和Token是最常见和广泛使用的三种机…

C++基础知识(三) -- 引用

1 引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名(俗称)&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称"…

动态内存管理<C语言>

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

深度学习基础之GFLOPS(2)

什么是GFLOPS 神经网络的GFLOPS&#xff08;Giga FLoating-Point Operations Per Second&#xff09;代表了神经网络模型执行计算的速度和计算能力。这可以用一个类比来解释&#xff1a; GFLOPS就像神经网络模型的"运算速度"标签。 想象你有两个数学家&#xff0c…

macOS下 /etc/hosts 文件权限问题修复方案

文章目录 前言解决方案权限验证 macOS下 etc/hosts 文件权限问题修复 前言 当在 macOS 上使用 vi编辑 /etc/hosts 文件时发现出现 Permission Denied 的提示,就算在前面加上 sudo 也照样出现一样的提示,解决方案如下; 解决方案 可以尝试使用如下命令尝试解除锁定; sudo chf…

Spring5应用之Cglib动态代理

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Spring5应用专栏_Aomsir的博客-CSDN博客 文章目录 前言Cglib动态代理…