哈希表里的“垃圾元素”,为什么有时必须删除?

哈希表里的“垃圾元素”,为什么有时必须删除?

◆ 博主名称: 晓此方-ZEEKLOG博客

大家好,欢迎来到晓此方的博客。

⭐️C++系列个人专栏:

Re:从零开始的C++_晓此方的博客-ZEEKLOG博客

 ⭐️踏破千山志未空,拨开云雾见晴虹。 人生何必叹萧瑟,心在凌霄第一峰


目录

一、什么是哈希表中的垃圾元素

二、什么时候必须清理垃圾元素

2.1情况1:需要比较两个哈希表是否相等

2.2情况2:算法依赖 map.size()

三、什么时候不需要清理

四、从刷题中总结出来的实战经验


一、什么是哈希表中的垃圾元素

        在做滑动窗口 + 哈希统计时,经常会出现一种现象:哈希表中存在 value = 0 的键值对。这些元素通常被称为 “垃圾元素”

        当我们做频率统计时,经常写这样的代码:

mp[x]--; 

        如果x原来是1,执行后变成了0但在map / unordered_map中:(xxx,0)仍然是一个真实存在的键值对,并不会自动删除。这种 key 仍存在,但 value 已经没有意义 的元素,就可以称为:哈希表垃圾元素(value = 0 的 key)


二、什么时候必须清理垃圾元素

        先说结论,核心原则:

        只要你的算法依赖“哈希表结构”进行判断,就必须清理。

2.1情况1:需要比较两个哈希表是否相等

典型例题:

LCR 015. 找到字符串中所有字母异位词 - 力扣(LeetCode)https://leetcode.cn/problems/VabMRr/description/本人有两解:

class Solution { public: vector<int> findAnagrams(string s, string p) { vector<int> v; map<char, int> sc1; map<char, int> sc2; for (auto e : p) { sc2[e]++; } string::iterator left = s.begin(); string::iterator right = s.begin(); for (int i = 0; i < p.size(); i++) { if (right == s.end()) return v; sc1[*right]++; right++; } while (right != s.end()) { if (sc1 == sc2) { v.push_back(left - s.begin()); } sc1[*right]++; right++; sc1[*left]--; if (sc1[*left] == 0) sc1.erase(*left); left++; } if (sc1 == sc2) { v.push_back(left - s.begin()); } return v; } };
class Solution { public: vector<int> findAnagrams(string s, string p) { map<char,int> mp1; map<char,int> mp2; for(auto e:p){mp2[e]++;} int m=p.size(); int n=s.size(); string ::iterator left=s.begin(); string ::iterator right=s.begin(); int count=0; vector<int> v; while(right!=s.end()) { mp1[*right]++; if(mp2.find(*right)!=mp2.end()&&mp1[*right]<=mp2[*right]) count++; while((right-left+1)>m) { if(mp2.find(*left)!=mp2.end()&&mp1[*left]<=mp2[*left]) count--; mp1[*left]--; if(mp1[*left]==0) mp1.erase(*left); left++; } if(count==m) v.push_back(left-s.begin()); right++; } return v; } };

        我们看第一解中的片段:if (sc1 == sc2) {v.push_back(left - s.begin()); 如果窗口移动时只写:sc1[*left]--;left++;没有删除:if (sc1[*left] == 0) sc1.erase(*left);就可能出现:

mp1: a -> 1 b -> 1 mp2: a -> 1 b -> 1 c -> 0 

        虽然频率逻辑是正确的,map 判断时:mp1 != mp2。因为mp2多了一个 key。结果:算法会 漏掉正确答案。因此:value == 0 必须 erase。

2.2情况2:算法依赖 map.size()

        如果代码中出现:mp.size()来判断窗口状态,例如:窗口内不同字符数量那么:value = 0 的 key,会导致:size 统计错误。例如:

a -> 1 b -> 1 c -> 0 

        此时:size = 3。但实际上窗口里只有:2 个有效字符,因此必须删除。

if (mp[x] == 0) mp.erase(x); 

三、什么时候不需要清理

        如果你的算法 只关心频率值,例如:

mp[a] <= mp[b] mp[a] >= mp[b] mp[a]++ mp[a]-- 

不比较 map 结构,通常可以不删除。典型例题:

30. 串联所有单词的子串 - 力扣(LeetCode)https://leetcode.cn/problems/substring-with-concatenation-of-all-words/description/本人有一解:(这里故意修改了一些代码方便下面讲解)

class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { vector<int> v; map<string, int> mp1; map<string, int> mp2; for (auto e : words) { mp1[e]++; } int len = words[0].size(); int n = words.size(); int lengthen = len * n; int count = 0; for (int i = 0; i < len; i++) { int right = i, left = i; while (right < s.size()) { mp2[s.substr(right, len)]++; if (mp1.find(s.substr(right, len)) != mp1.end() && mp2[s.substr(right, len)] <= mp1[s.substr(right, len)]) { count++; } if (right - left + len > lengthen) { if (mp1.find(s.substr(left, len)) != mp1.end() && mp2[s.substr(left, len)] <= mp1[s.substr(left, len)]) { count--; } mp2[s.substr(left, len)]--; if (mp2[s.substr(left, len)]==0) { mp2.erase(s.substr(left, len)); } left += len; } if (count == n) v.push_back(left); right += len; } mp2.clear(); count = 0; } return v; } };

        在这题中常见判断是:即使存在:s.substr(right, len) -> 0也不会影响逻辑正确性。因此 删除只是优化,不是必须

mp2[s.substr(right, len)] <= mp1[s.substr(right, len)] 

        实际上这里的判断和删除逻辑并非必须,不需要像我一样这么冗余,但是加上mp1.find(s.substr(left, len)) != mp1.end()的判断效率会高很多。

if (mp1.find(s.substr(left, len)) != mp1.end() && mp2[s.substr(left, len)] <= mp1[s.substr(left, len)]) { count--; } mp2[s.substr(left, len)]--; if (mp2[s.substr(left, len)]==0) { mp2.erase(s.substr(left, len)); }

四、从刷题中总结出来的实战经验

        写滑动窗口哈希表时,可以记住一个简单规则:如果代码中出现:map1 == map2或者是map.size()。就必须写:

if (mp[key] == 0) mp.erase(key); 

        否则很容易出现隐藏 bug。如果只是做 频率比较,通常可以不删。

当算法依赖 哈希表结构(keys) 时必须去污;
当算法只依赖 哈希表数值(values) 时通常不必去污。

好了,本期内容到此结束,我是此方,我们下期再见。バイバイ!

Read more

Flutter 三方库 jwt_io 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、严谨、全能的 JSON Web Token (JWT) 加解密与身份安全验证引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 jwt_io 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、严谨、全能的 JSON Web Token (JWT) 加解密与身份安全验证引擎 在鸿蒙(OpenHarmony)系统的端云一体化登录、政企应用的安全审计或复杂的跨端权限校验场景中,如何确保来自云端授信中心的 JWT Token 既能被正确解析(Decode),又能被严密地校验其合法性与过期时间?jwt_io 为开发者提供了一套工业级的、基于 RFC 7519 标准的 JSON Web Token 深度处理方案。本文将深入实战其在鸿蒙应用安全底座中的应用。 前言 什么是 JWT IO?它不仅是一个简单的 Base64 解码器,而是一个具备深厚 RFC

By Ne0inhk

微算法科技(NASDAQ: MLGO)使用量子傅里叶变换(QFT),增强图像压缩和滤波效率

在人工智能与量子计算深度融合的浪潮中,传统图像处理技术面临效率瓶颈。经典傅里叶变换(DFT)虽能将图像从空间域转换至频率域以实现压缩与滤波,但其计算复杂度随数据规模指数增长,难以满足实时性需求。量子计算凭借量子叠加与纠缠特性,为高频图像处理提供了突破口。微算法科技(NASDAQ :MLGO)敏锐捕捉到量子傅里叶变换(QFT)的潜力——作为经典DFT的量子版本,QFT可在多项式时间内完成频域转换,将图像压缩效率提升指数级,同时通过量子并行性优化滤波精度。这一技术突破为高分辨率遥感、医学影像分析等场景提供了高效解决方案。 量子傅里叶变换(QFT)是量子计算中实现时频域转换的核心算法,其本质是通过量子态叠加与干涉,将输入量子态的相位信息从空间域映射至频率域。 与传统DFT相比,QFT的输出为量子叠加态,需通过测量获取概率分布。其核心优势在于利用量子并行性,将计算复杂度从经典DFT的O(n2n)降至O(n2),同时通过相位旋转门实现相干叠加,突破经典复数乘加运算的线性限制。微算法科技将QFT引入图像处理,通过量子电路设计将图像数据编码为量子态,在频域中高效完成压缩与滤波操作。 量子态编码

By Ne0inhk
【数据结构指南】深入二叉树遍历

【数据结构指南】深入二叉树遍历

前言:         在前文中,我们探讨了完全二叉树和满二叉树的概念与性质,并基于完全二叉树实现了堆这一数据结构。然而,对于普通二叉树的认识仍有待深入,本文将系统性地介绍普通二叉树的遍历相关内容。                   一、前置说明          一般而言,对于一棵普通二叉树是通过链式结构定义,即每个节点包含三个部分:          1.数据域(data):用于存储节点的值          2.左指针(left):用于指向左子节点          3.右指针(right):用于指向右子节点                  typedef int BTDataType;//此处将 (int)整形 作为节点存储的内容 typedef struct BinaryTree { BTDataType data; struct BinaryTree* left; struct BinaryTree* right; }BTNode;                  在学习二叉树的基本操作前,需先要先创建一棵二叉树,然后才能学习

By Ne0inhk
我的算法修炼之路--9——重要算法思想:贪心、二分、正难则反、多重与完全背包精练

我的算法修炼之路--9——重要算法思想:贪心、二分、正难则反、多重与完全背包精练

💗博主介绍:计算机专业的一枚大学生 来自重庆 @燃于AC之乐✌专注于C++技术栈,算法,竞赛领域,技术学习和项目实战✌💗 💗根据博主的学习进度更新(可能不及时) 💗后续更新主要内容:C语言,数据结构,C++、linux(系统编程和网络编程)、MySQL、Redis、QT、Python、Git、爬虫、数据可视化、小程序、AI大模型接入,C++实战项目与学习分享。 👇🏻 精彩专栏 推荐订阅👇🏻 点击进入🌌作者专栏🌌: Linux系统编程✅ 算法画解 ✅ C++ ✅ 🌟算法相关题目点击即可进入实操🌟 感兴趣的可以先收藏起来,请多多支持,还有大家有相关问题都可以给我留言咨询,希望希望共同交流心得,一起进步,你我陪伴,学习路上不孤单! 文章目录 * 前言 * 题目清单 * 1.Space Elevator 太空电梯

By Ne0inhk