当前位置: 首页 > news >正文

Leetcode热题100(8-12)

目录

一、最小覆盖子串(LeetCode 76):滑动窗口的经典范式

二、找到字符串中所有字母异位词(LeetCode 438):滑动窗口+哈希表的细节把控

三、和为K的子数组(LeetCode 560):前缀和+哈希表的巧妙结合

四、滑动窗口最大值(LeetCode 239):优先队列(大顶堆)的实战

 五、内存池PopRange异常:实战踩坑之“访问权限冲突” 

六、总结:算法思维与C++工具的融合


在C++算法学习的路上,刷题是提升编程能力的必经之路。本文将围绕几道LeetCode经典题目,带你深入理解滑动窗口、哈希表、优先队列等核心技术的实战应用,从代码实现到原理剖析,助力你在算法进阶之路上更进一步。
 

一、最小覆盖子串(LeetCode 76):滑动窗口的经典范式


问题描述:给定字符串 s 和 t ,找出 s 中涵盖 t 所有字符的最小子串,若不存在则返回空字符串。
 
核心思路:
 
- 用两个哈希表 hash1 (记录 t 的字符及数量)、 hash2 (记录窗口内字符及数量)。
- 维护 left 和 right 双指针构成滑动窗口,通过 count 和 kinds 判断窗口是否覆盖 t 的所有字符,进而缩小窗口找最小值。
 
代码解析:

class Solution {
public:string minWindow(string s, string t) {int hash1[128] = {0}, hash2[128] = {0};int kinds = 0;for (auto e : t) {if (hash1[e] == 0) kinds++;hash1[e]++;}int left = 0, right = 0, begin = -1, minlen = INT_MAX, count = 0;for (; right < s.size(); right++) {hash2[s[right]]++;if (hash2[s[right]] == hash1[s[right]]) count++;while (count == kinds) {if (minlen > right - left + 1) {minlen = right - left + 1;begin = left;}if (hash2[s[left]] == hash1[s[left]]) count--;hash2[s[left]]--;left++;}}if (begin == -1) return "";else return s.substr(begin, minlen);}
};

关键理解:
 
-  kinds 记录 t 中不同字符的种类, count 记录窗口中“已满足 t 字符数量要求”的种类数。当 count == kinds 时,窗口完全覆盖 t 。
- 滑动窗口的“扩大”与“缩小”交替进行,确保在O(n)时间复杂度内解决问题(n为 s 的长度)。
 

二、找到字符串中所有字母异位词(LeetCode 438):滑动窗口+哈希表的细节把控


问题描述:给定 s 和 p ,找出 s 中所有 p 的异位词(字符组成相同、顺序不同的子串)的起始索引。
 
核心思路:
 
- 用哈希表 hash1 记录 p 的字符频率, hash2 记录窗口内字符频率。
- 维护固定长度( p.size() )的滑动窗口,每次窗口满时,比对 hash1 和 hash2 的字符频率是否完全一致。
 
代码解析:

class Solution {
public:vector<int> findAnagrams(string s, string p) {unordered_map<char, int> hash1;unordered_map<char, int> hash2;vector<int> v;for (auto e : p) {hash1[e]++;}int left = 0, right = 0;for (; right < s.size(); right++) {int len = right - left + 1;hash2[s[right]]++;if (len == p.size()) {int flag = 1;for (char i = 'a'; i <= 'z'; i++) {if (hash1[i] != hash2[i]) {flag = 0;break;}}if (flag == 1) v.push_back(left);hash2[s[left]]--;left++;}}return v;}
};

优化思考:
 
- 上述代码中“遍历a-z比对哈希表”的操作可优化,通过维护“匹配种类数”来替代,进一步降低时间复杂度(类似“最小覆盖子串”的 count 思路)。
 

三、和为K的子数组(LeetCode 560):前缀和+哈希表的巧妙结合


问题描述:给定整数数组 nums 和整数 k ,统计和为 k 的子数组个数。
 
核心思路:
 
- 利用前缀和思想, sum[i] 表示前 i 个元素的和。若 sum[j] - sum[i] = k ,则 [i+1, j] 子数组的和为 k 。
- 用哈希表 hash 记录“前缀和出现的次数”,遍历数组时动态统计符合条件的子数组数量。
 
代码解析:


class Solution {
public:int subarraySum(vector<int>& nums, int k) {unordered_map<int, int> hash;hash[0] = 1; // 处理前缀和刚好为k的情况(如nums[0..i]和为k)int sum = 0, ret = 0;for (auto e : nums) {sum += e;if (hash.count(sum - k)) ret += hash[sum - k];hash[sum]++;}return ret;}
};


 
关键理解:
 
-  hash[0] = 1 是边界条件的关键,确保当 sum 本身等于 k 时(即子数组以第0个元素为起点)能被正确统计。
- 哈希表的时间复杂度为O(1),因此整体算法时间复杂度为O(n)(n为 nums 长度)。
 

四、滑动窗口最大值(LeetCode 239):优先队列(大顶堆)的实战


问题描述:给定整数数组 nums 和滑动窗口大小 k ,返回每个窗口的最大值。
 
核心思路:
 
- 用**优先队列(大顶堆)**存储窗口内的元素及索引,堆顶始终是当前窗口的最大值。
- 窗口滑动时,若堆顶元素的索引不在当前窗口内,将其弹出,确保堆顶始终是有效最大值。
 
代码解析:


class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();if (n == 0 || k == 0) return {};vector<int> res;priority_queue<pair<int, int>> pq; // 存储(元素值,索引),大顶堆// 初始化:将前k个元素入堆for (int i = 0; i < k; ++i) {pq.push({nums[i], i});}res.push_back(pq.top().first);// 滑动窗口移动for (int i = k; i < n; ++i) {pq.push({nums[i], i});// 移除堆顶中索引不在当前窗口内的元素while (pq.top().second <= i - k) {pq.pop();}res.push_back(pq.top().first);}return res;}
};


 复杂度分析:
 
- 优先队列的插入和弹出操作时间复杂度为O(log n),因此整体时间复杂度为O(n log n)(n为 nums 长度)。
- 若需进一步优化,可使用单调队列将时间复杂度降至O(n),思路是维护一个“单调递减”的双端队列,确保队首始终是窗口最大值。

五、无重复字符的最长子串(LeetCode 3):滑动窗口的入门典范


问题描述:给定字符串 s ,找出其中不含有重复字符的最长子串的长度。
 
核心思路:
 
- 用 left 和 right 双指针维护无重复字符的滑动窗口,用长度为128的数组 hash 记录窗口内字符的出现次数(利用ASCII字符范围优化效率)。
- 右指针 right 不断扩张窗口,若当前字符重复,则左指针 left 收缩窗口,直到无重复,过程中更新最长子串长度。
 
代码解析:


class Solution {
public:int lengthOfLongestSubstring(string s) {int left = 0, right = 0;  // 滑动窗口左右边界int hash[128] = {0};     // 记录字符出现次数(ASCII字符范围0-127)int n = s.size();int maxLen = 0;          // 最长无重复子串长度while (right < n) {hash[s[right]]++;  // 右指针字符加入窗口// 若字符重复,左指针收缩窗口while (hash[s[right]] > 1) {hash[s[left++]]--;}// 更新最长长度(窗口长度为right - left + 1)maxLen = max(maxLen, right - left + 1);right++;  // 右指针继续扩张}return maxLen;}
};

关键理解:
 
- 数组 hash 替代 unordered_map ,将空间复杂度从O(字符种类)优化到O(1)(固定128长度)。
- 窗口“扩张-收缩”的过程确保每个字符最多被访问两次(左、右指针各一次),时间复杂度为O(n)。

六、总结:算法思维与C++工具的融合


- 算法层面:滑动窗口、哈希表、优先队列是解决数组/字符串问题的核心武器,掌握它们的原理和代码模板是刷题进阶的关键。
- 工程层面:内存访问、断言逻辑、指针操作是常见“踩坑点”,调试时要关注异常提示的上下文,从逻辑合法性和内存安全性两方面排查问题。
 
无论是算法题的“逻辑闯关”,还是工程代码的“bug 狩猎”,扎实的C++基础和清晰的思维逻辑都是制胜法宝。希望本文的多维度分享,能为大家的C++学习之路添砖加瓦~

http://www.dtcms.com/a/434639.html

相关文章:

  • 六站合一的优势123上网之家网址
  • C++中的多线程编程及线程同步
  • 湛江做网站从微信运营方案
  • 伊吖学C笔记(8、结构体、链表、union、enum、typedef)
  • 2022 年真题配套词汇单词笔记(考研真相)
  • HTML5消费收入矩阵计算器
  • 霸州做阿里巴巴网站庆安建设局网站
  • PCB学习——STM32F103VET6-STM32主控部分
  • 大学生作业做网站网站建设公司比较
  • 写一个星河社区aistudio大模型部署之后的AI agent转发程序
  • 网站上的中英文切换是怎么做的wordpress页面移动端
  • 八、Scala 集合与函数式编程
  • 腾讯CODING Maven的aar制品添加上传流程
  • Effective Modern C++ 条款29: 移动语义的局限性与实践指南
  • 2025年渗透测试面试题总结-98(题目+回答)
  • 深圳网站制作 公司wordpress备份百度云
  • 《时序数据监控平台优化指南:从查询超时到秒级响应,指标下的存储与检索重构实践》
  • 新版android studio创建项目的一些问题
  • 做企业网站有哪些好处软件技术买什么笔记本好
  • 【Redis】Redis的5种核心数据结构和实战场景对应(在项目中的用法)
  • Vue 与 React 深度对比:技术差异、选型建议与未来趋势
  • 创意网站页面wordpress预约小程序
  • Android_framework-odex优化
  • RAG核心特性:文档过滤和检索
  • 26.awk 使用手册
  • AI应用开发新范式:从模型API到交互式网页的极速实现路径
  • 网站建设2017主流代码语言太原百度快照优化排名
  • Python学习之day02学习(函数模块的上传、数据类型+)
  • 可以下载的建站网站河南省建设厅门户网站
  • [创业之路-661]:采集狩猎社会的主要技术、技术产业链以及产要产品