哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用

上一节介绍了哈希表的原理与设计方法,这一节则直接python中现有的哈希表类型:哈希集合 set(集合)和哈希映射 dict(字典)来解决实际应用(刷题)。

零、概念
在介绍实际应用之前,有一个概念我认为是应该了解的,那就是可哈希hashable)。官方的术语介绍如下:

一个对象的哈希值如果在其生命周期内绝不改变,就被称为 可哈希 (它需要具有 __hash__() 方法),并可以同其他对象进行比较(它需要具有 __eq__() 方法)。可哈希对象必须具有相同的哈希值比较结果才会相同。

可哈希性使得对象能够作为字典键或集合成员使用,因为这些数据结构要在内部使用哈希值。

大多数 Python 中的不可变内置对象都是可哈希的;可变容器(例如列表或字典)都不可哈希;不可变容器(例如元组和 frozenset)仅当它们的元素均为可哈希时才是可哈希的。 用户定义类的实例对象默认是可哈希的。 它们在比较时一定不相同(除非是与自己比较),它们的哈希值的生成是基于它们的 id()

我的理解就是:由于python实现的集合和字典是基于哈希表或哈希函数的,为了确保键的唯一性(键与哈希值一 一对应),则规定集合成员字典中的键必须是可哈希的,这意味着其值在其生命周期内不会改变,所以又叫做不可变的。这样, Python 就可以创建一个唯一的哈希值来识别它,字典可以使用它来跟踪唯一键和集合来跟踪唯一值。

不可变类型(immutable types):int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

可变类型(mutable types):list, dict, set, bytearray, user-defined classes

一、哈希集合的应用

集合是用来存储非重复值的数据结构,因此,很自然地想到用集合进行查重和去重。

217.存在重复元素

class Solution:def containsDuplicate(self, nums: List[int]) -> bool:hashset = set()  # 初始化for i in nums:if i in hashset:  # 元素是否为集合的成员return Trueelse:hashset.add(i)  # 元素添加到集合return False

136. 只出现一次的数字

class Solution:def singleNumber(self, nums: List[int]) -> int:ans = set()for num in nums:if num in ans:ans.remove(num)else:ans.add(num)return ans.pop()

虽然可以用集合解决,但是此题最优的做法是位运算,原理是相同的数做异或运算 ^ 会得到0,而一个数与0做异或会得到这个数本身。所以,数组里面所有相同的数异或会得到0,而那个只出现一次的数再与0做异或,直接得到结果本身,代码如下:

class Solution:def singleNumber(self, nums: List[int]) -> int:ans = nums[0]for i in range(1, len(nums)):ans = ans ^ nums[i]return ans

349. 两个数组的交集

用自带的set,显然 return list(set(nums1) & set(nums2)) 即可,如果是自己实现取交集的操作呢?

class Solution:def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:set1 = set(nums1)set2 = set(nums2)return self.set_intersection(set1, set2)def set_intersection(self, set1, set2) -> List[int]:if len(set1) > len(set2):  #  考虑较小的数组return self.set_intersection(set2, set1)return [x for x in set1 if x in set2]

小技巧,两个数组的交集一定是在较小的数组当中。

202. 快乐数

class Solution:def isHappy(self, n: int) -> bool:notHappy = set()while True:numbers = list(str(n))total = 0for number in numbers:total += int(number) ** 2if total == 1:return Trueelif total in notHappy:  # 陷入无限循环return Falseelse:notHappy.add(total)n = total

不停重复这个过程,直到这个数等于1(是快乐数),或者这个数等于之前出现过的数(陷入无限循环)。

二、哈希映射的应用

哈希映射是用于存储 (key, value) 键值对的一种实现,这意味着,我们在需要存储比键 key 的信息更多的信息(值 value 的信息)时,需要用到哈希映射。python中的对应自带类型为字典 dict。

1. 两数之和

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:record = dict()for i, num in enumerate(nums):if target - num in record:return [record[target - num], i]else:record[num] = i

这里的字典,就不仅存放了 nums 中不同元素的索引(作为键 key),还存放了 target - num 的值(作为值 value),这样当有元素等于这个值时,说明它们之和为target,同时可以输出它们的对应索引(键 key)。

更多关于两数、三数、四数之和的题解,可以看我的这篇文章。

205. 同构字符串

class Solution:def isIsomorphic(self, s: str, t: str) -> bool:s_table = dict()t_table = dict()for i in range(len(s)):if (s[i] in s_table and s_table[s[i]] != t[i]) or (t[i] in t_table and t_table[t[i]] != s[i]):return Falseelse: if s[i] not in s_table:s_table[s[i]] = t[i]  # s到t的关系if t[i] not in t_table:t_table[t[i]] = s[i]  # t到s的关系return True

判断两个字符串是否同构,即存在某种对应关系,注意这个关系得是双向成立的,因为可能字符串1中 a -> b 一定成立,但是字符串2中 b -> a 不一定成立。

599. 两个列表的最小索引总和

class Solution:def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]:RestaurantTable = dict()ans = list()num = 2005  # 大于2000即可for i, restaurant1 in enumerate(list1):RestaurantTable[restaurant1] = ifor j, restaurant2 in enumerate(list2):if restaurant2 in RestaurantTable and RestaurantTable[restaurant2] + j <= num:if RestaurantTable[restaurant2] + j < num:ans.clear()ans.append(restaurant2)num = RestaurantTable[restaurant2] + jelse:ans.append(restaurant2)return ans

用字典记录一个数组中的餐厅和对应索引值,再遍历另一个数组,如果出现同一个餐厅并且索引之和小于等于当前的最小值 num,则更新 ans 和 num(小于)或者添加餐厅到 ans(等于)。

387. 字符串中的第一个唯一字符

class Solution:def firstUniqChar(self, s: str) -> int:Hashtable = dict()for i, char in enumerate(s):if char in Hashtable:Hashtable[char] = -1else:Hashtable[char] = ians = len(s)for char in Hashtable:if Hashtable[char] != -1 and Hashtable[char] < ans:ans = Hashtable[char]return ans if ans != len(s) else -1

遍历字符串,新出现的字符记录其索引,后面如果重复出现该字符,则值变成 -1(无论多少次出现都是 -1)。然后从ans = len(s) 开始,找到具有最小索引值的字符,若不存在则返回 -1。

350. 两个数组的交集 II

class Solution:def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:if len(nums1) > len(nums2):return self.intersect(nums2, nums1)c = collections.Counter()for n in nums1:c[n] += 1     ans = list()for m in nums2:if m in c and c[m] > 0:ans.append(m)c[m] -= 1return ans

开头还是小技巧,交集一定在较小的数组中。然后这里用到的是计数器类型 collections.Counter(),它是一个 dict 的子类,用于计数可哈希对象。它的特点就是如果引用的键没有任何记录,就返回一个0,而不是报错 KeyError 。这里的计数器用于存放元素在数组 nums1 出现的次数,然后遍历数组 nums2,每次边添加结果边计数器减一。这样就能使得输出结果中每个元素出现的次数,与元素在两个数组中出现次数的最小值一致。

219. 存在重复元素 II

class Solution:def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:hashtable = dict()for i, num in enumerate(nums):if num in hashtable and abs(i - hashtable[num]) <= k:return Trueelse:hashtable[num] = ireturn False

用字典记录元素和它的索引值,后面出现相同元素时判断是否符合条件,不符合条件就更新索引值(离下一个相同元素更近)。

220. 存在重复元素 III

class Solution:def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:table = dict()for i in range(len(nums)):bucket_num = nums[i] // (t + 1) # 取商数作为桶的编号,每个桶大小为 t + 1# 存在当前编号的桶,即桶里面已经有东西了,则它们的值一定相差不大于 tif bucket_num in table:return Truetable[bucket_num] = nums[i]# 存在上一个编号的桶,到里面看看是否符合条件if (bucket_num - 1) in table and abs(table[bucket_num - 1] - nums[i]) <= t:return True# 存在下一个编号的桶,到里面看看是否符合条件if (bucket_num + 1) in table and abs(table[bucket_num + 1] - nums[i]) <= t:return True# 当 i 大于等于 k 时,下次遍历(i + 1)就不能考虑 nums[i-k] 了if i >= k:table.pop(nums[i - k] // (t + 1))return False

这题的核心思想就是分桶(分组),将遍历得到的数按数值范围放入不同的桶中(注意是取商数分桶而不是取余数),每个桶的大小为 t + 1。这样当有两个数出现在同一个桶时,它们的差距一定是小于等于 t 的;同一个桶中只有一个的话,就到相邻的桶看看是否符合条件,不相邻的桶就不用考虑了(值的差距一定大于 t);最后要把距离当前索引 k 的那个值对应的桶删掉(索引的差距大于 k)。

359. 日志速率限制器

class Logger:def __init__(self):"""Initialize your data structure here."""self.hashtable = dict()def shouldPrintMessage(self, timestamp: int, message: str) -> bool:"""Returns true if the message should be printed in the given timestamp, otherwise returns false.If this method returns false, the message will not be printed.The timestamp is in seconds granularity."""if message in self.hashtable:if timestamp >= self.hashtable[message]:self.hashtable[message] = timestamp + 10return Trueelse:return Falseelse:self.hashtable[message] = timestamp + 10return True

用字典记录信息和它下一次可以打印的时间,实际上只有打印过并且没到下一次时间的信息会返回False,其余都是更新时间并返回True。

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

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

相关文章

leetcode518. 零钱兑换 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个满足答案的结果有很多种&#xff0c;所以我们可以用动态规划去做,那么题意中我们可以知道的是我们是可以输入一种面值的时候,我们是可以重复输入的&#xff0c;那么这就是背包类型中的完全背包了2.动态规划5步…

跟我一起学.NetCore之选项(Options)核心类型简介

前言.NetCore中提供的选项框架&#xff0c;我把其理解为配置组&#xff0c;主要是将服务中可供配置的项提取出来&#xff0c;封装成一个类型&#xff1b;从而服务可根据应用场景进行相关配置项的设置来满足需求&#xff0c;其中使用了依赖注入的形式&#xff0c;使得更加简单、…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之下——设计键

在很多应用中&#xff0c;我们会发现某种映射关系&#xff08;模式&#xff09;&#xff0c;但它并不是简单一 一对应的。这时&#xff0c;我们就要从键 key 入手&#xff0c;通过设计合适的键&#xff0c;建立映射关系。leetbook的这个章节总结了一些常见的键&#xff0c;以供…

《ASP.NET Core项目开发实战入门》送书活动结果公布

截至2020.09.20 本次送书活动《ASP.NET Core项目开发实战入门》。下面把Top 5的留言截图给大家回顾一下。以下5位同学将获赠书籍一本&#xff1a;小林子鉴静红脸先生阿星Plus以上同学请在2020年9月25日24&#xff1a;00之前加小二微信领取赠书&#xff0c;超过时间视为放弃。小…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型

二分查找的定义如下&#xff08;引自Wiki&#xff09;&#xff1a; 在计算机科学中&#xff0c;二分查找算法&#xff08;英语&#xff1a;binary search algorithm&#xff09;&#xff0c;也称折半搜索算法&#xff08;英语&#xff1a;half-interval search algorithm&…

Magicodes.IE 2.3重磅发布——.NET Core开源导入导出库

在2.3这一版本的更新中&#xff0c;我们迎来了众多的使用者、贡献者&#xff0c;在这个里程碑中我们也添加并修复了一些功能。对于新特点的功能我将在下面进行详细的描述&#xff0c;当然也欢迎更多的人可以加入进来&#xff0c;再或者也很期待大家来提issues或者PR&#xff0c…

听说用 C# 写 TensorFlow 更高效?

经过半年呕心沥血的努力&#xff0c;SciSharp STACK终于把Tensorflow .NET绑定升级到可以使用 tensorflow 2.3, 新版本最大的优势是实现了Eager模式, 这个特性是让.NET C#/ F#成为机器学习模型开发工具的重要前置条件。NugGet包下载:https://www.nuget.org/packages/TensorFlow…

leetcode279. 完全平方数

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个就是将一个数分成几个数的和;然而的话,这几个数必须的是完全平方数,我们要求的是最少数量的完全平方数这个满足答案的有好几个;但是我们要求的是最少的数量2.动态规划五步走1>:确定dp数组的含义以及下标的含…

岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)

695. 岛屿的最大面积 先上最经典的题目&#xff0c;详细思路看这题的官方题解&#xff0c;简单来说的岛屿问题就是遍历二维数组&#xff0c;一般都是从一块陆地开始&#xff0c;进行深度优先或者广度优先搜索&#xff0c;每次上下左右四个方向选其一然后寻找下一块陆地&#x…

跟我一起学.NetCore之Options实例演示及分析

前言来啦&#xff01;来啦&#xff01;上一节一堆代码&#xff0c;是不是感觉甚是无味啊&#xff1f;没关系&#xff0c;这里结合上一节内容专注举例演示&#xff0c;绝不废话&#xff01;走起~~~~~正文老规矩&#xff0c;一个WebApi项目走起&#xff0c;项目结构如下&#xff…

leetcode139. 单词拆分

一:题目 二:上码 class Solution { public:/**思路:1.分析题意单词就是物品;字符串就是背包;单词能否组成字符串就是在问,物品能不能将背包装满单词可以重复使用那么说明这是一个完全背包2.动态规划五步走1>:确定dp数组的与下标的含义&#xff08;这里用下标i是由我们的遍历…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型

二分查找的讲解请见上一篇文章。本文主要记录对数值进行二分的题目解法与思路。 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> int:left 1right nwhile left < right:mid left (right - left) // 2if guess(mid) 1: # mid < pickleft mi…

大数据下的质量体系建设

一、背景大数据、人工智能是当前也是未来几年IT部门的重点建设方向&#xff0c;新的技术可以为业务突破盈利瓶颈&#xff0c;带来新的增长点&#xff0c;同时我们也发现数据中台也频频在最近的企业财报予以体现&#xff0c;相关的技术岗位需求也是供不应求&#xff0c;与之形成…

Pandas中的 transform() 结合 groupby() 用法示例

首先&#xff0c;假设我们有如下餐厅数据集&#xff1a; import pandas as pddf pd.DataFrame({restaurant_id: [101,102,103,104,105,106,107],address: [A,B,C,D, E, F, G],city: [London,London,London,Oxford,Oxford, Durham, Durham],sales: [10,500,48,12,21,22,14] })…

跟我一起学.NetCore之日志(Log)模型核心

前言鲁迅都说&#xff1a;没有日志的系统不能上线(鲁迅说&#xff1a;这句我没说过&#xff0c;但是在理)&#xff01;日志对于一个系统而言&#xff0c;特别重要&#xff0c;不管是用于事务审计&#xff0c;还是用于系统排错&#xff0c;还是用于安全追踪.....都扮演了很重要的…

Numpy中数组创建函数的辨析

首先推荐Numpy官方的教程&#xff0c;网址。 很多人会对数组创建函数的参数中什么时候要用括号np.zeros((2, 3))&#xff0c;什么时候不用括号np.eye(3, 5)感到疑惑&#xff0c;这里对它们统一进行梳理。&#xff08;按照官方文档的分类方法&#xff09; 1. 一维数组创建函数…

leetcode213. 打家劫舍 II

一:题目 二:上码 class Solution { public:/**思路:1.既然成环了,我们如果选取得一条偷取路径是从头开始得那么我们就不能偷取最后一个,那就不算最后一个偷取一遍2.同理我们也可以不算第一个 偷取一遍计算一次偷取得结果*/int rob(vector<int>& nums) {if(nums.size…

如何使用 C# 中的 ValueTask

在 C# 中利用 ValueTask 避免从异步方法返回 Task 对象时分配翻译自 Joydip Kanjilal 2020年7月6日 的文章 《How to use ValueTask in C#》(https://www.infoworld.com/article/3565433/how-to-use-valuetask-in-csharp.html)异步编程已经使用了相当长一段时间了。近年来&…

一文弄懂Numpy中ndarray的维度(dimension)/轴数(axis/axes)问题

Numpy库的核心是ndarray&#xff0c;实际上就是N维数组&#xff08;N-dimensional array&#xff09;&#xff0c;关于这个数据对象的详细介绍&#xff0c;参考官方文档最为合适。有一点要注意的是&#xff0c;ndarray的内置方法只有30多个&#xff0c;常用的如求平均值可以写a…

leetcode337. 打家劫舍 III

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*…