折叠

LeetCode-217. 存在重复元素(字典、Set去重的底层原理哈希表)

题目:

 

解题代码:

(1)Set去重法:

点击查看代码
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        return len(set(nums)) < len(nums)

(2)字典:

点击查看代码
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        all_dict = {}
        for i in nums:
            if i not in all_dict:
                all_dict[i] = 1
            else:
                return True
        return False

补充知识:

1、哈希表

参考:https://zhuanlan.zhihu.com/p/144296454

  • 基本定义:别称是散列表,是一种数据结构。
  • 优点:提供了快速插入和查找操作,且两者的时间复杂度都为O(1)。
  • 缺点:基于数组,数组扩容成本高,哈希表填满后性能下降严重。
  • 基本思想:通过哈希函数将键(key)转换为数组下标(有时候不需要转换)
  • 哈希函数:将非int的键(key)转换为int,作为数组下标。
    • 需要满足三个条件
      • 通过哈希函数生成的哈希值是非负整数
      • 同一个key生成的哈希值一样
      • 不同的key生成的哈希值不一样 -> 生成的哈希值一样时产生哈希冲突
  • 解决哈希冲突
    • 开放地址法
      • 线性探测:
        • 线性探测插入:从已经存在元素的数组下标依次向下寻找空白存放
        • 线性探测查找:比较key与数组下标为key生成哈希值的元素,相等则找到,否则就依次向后查找,没找到说明元素不在哈希表中。
        • 线性探测的删除:不同于简单的直接删除对应数据,需要用特殊的数据顶替被删除的数据。因为多次使用删除操作会让特殊数据项占据哈希表导致哈希表效率下降,所以尽量少使用删除函数。
      • 二次探测:
        • 解决问题:线性探测哈希表中数据发生聚集后,后来的数据项都需要向后移动,二次探测要防止聚集的发生。
        • 基本思想:探测相隔较远的单元,而不是和原始位置相邻的单元。
        • 存在问题:映射到同一位置的key需要移动的位置是一样的,会产生二次聚集。
      • 双哈希:
        • 解决问题:消除原始聚集和二次聚集问题(探测步长固定)。
        • 基本思想:增加一个哈希函数根据key生成探测步长。
        • 第二个哈希函数特点:
          • 和第一个哈希函数不同
          • 不能输出0,经过实验“步长=constant - (key % constant)”的效果很好,constant是一个小于数组容量的质数。
        • 为什么需要哈希表容量的一个质数:保证探测过程能查找到哈希表的每一个位置。
    • 链表法
      • 基本思想:数组中的每个空位对应一条链表,当某个key的哈希值落在哈希表的某个位置,把该数据添加到链表中,这样就不需要找空位。
  • 哈希表效率:
    • 如果发生哈希冲突,插入和查找的时间复杂度会发生改变,和探测长度成正比,探测长度取决于装在因子,装载因子用来表示空位的多少。(装载因子 = 表中已存在的元素 / 表的长度)
  • 开放地址法与链表法的比较:
    • 开放地址法对于小型哈希表来说双哈希法比二次探测效果好。内存充足且哈希表不允许修改容量前提下线性探测效果好,装载因子低于0.5没有性能下降。
    • 在创建哈希表时,不知道存储数据的量,使用链表法比开放地址法好。
    • 两者均可选时使用链表法。

2、Python字典底层原理-哈希表:

参考:https://blog.csdn.net/qq_42815145/article/details/91353624

  • Python字典如何运用哈希表(仅补充本人不了解的):
    • 扩容:字典空间不够自动扩容时,会对已存在的键值对重新进行哈希函数运算保存到其它位置。
    • 碰撞:产生哈希冲突后的进行哈希表的一种非线性探测。
  • 字典相比列表的优势:
    • 列表查找是按顺序一个个遍历,列表越大,查找时间越久。
    • 字典通过键值直接计算得到对应的地址空间,查找一步到位。

3、Set()去重底层原理:

参考:https://blog.csdn.net/sinat_38682860/article/details/108057409

基本思想:set()方法首先调用hash()方法,哈希值不同则两者不同。如果得到两者的哈希值相同,会进行eq()操作判断两者原先的key是否相等,如果相等才会将两者认定为同一个,否则还是会去重。

posted @ 2021-11-29 20:23  Coverpast  阅读(73)  评论(0编辑  收藏  举报