代码随想录算法训练营Day6 | 哈希表理论基础、242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和 | Python | 个人记录向

注:Day5是休息日。

哈希表理论基础

代码随想录:哈希表理论基础

哈希表

哈希表(Hash Table)是根据关键码的值而直接进行访问的数据结构。一般哈希表都是用来快速判断一个元素是否出现集合里。查询的时间复杂度为O(1)

哈希函数(转载自代码随想录)

哈希函数
如果hashCode得到的数值大于哈希表的大小了,也就是大于tableSize了,怎么办呢?此时为了保证映射出来的索引数值都落在哈希表上,我们会在再次对数值做一个取模的操作,这样我们就保证了学生姓名一定可以映射到哈希表上了。

此时问题又来了,哈希表我们刚刚说过,就是一个数组。如果学生的数量大于哈希表的大小怎么办,此时就算哈希函数计算的再均匀,也避免不了会有几位学生的名字同时映射到哈希表同一个索引下标的位置。于是引出了哈希碰撞

哈希碰撞

两个数都映射到同一个哈希表位置上,这一现象称为哈希碰撞。一般有两种解决方法:拉链法和线性探测法。

拉链法

发生冲突的元素都被存储在链表中。

线性探测法

使用线性探测法,一定要保证tableSize大于dataSize。 我们需要依靠哈希表中的空位来解决碰撞问题。

例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放冲突的数据了。

常见的3种哈希结构

数组、set、map。代码随想录中主要讲解了C++的底层实现。这里看了一下python的相关底层实现。

  • 在Python中,set通过哈希表来实现。哈希表通过使用哈希函数来将元素的键映射到存储桶中的索引位置,从而实现快速的插入、删除和查找操作。每个元素的值都被哈希后存储在对应的桶中。
  • 在Python中,dict通过哈希表来实现。每个键值对在哈希表中都被存储在一个桶中,通过键的哈希值来确定存储的位置。当需要查找或更新某个键对应的值时,Python 会使用哈希函数计算键的哈希值,并在哈希表中定位到对应的桶,从而实现高效的操作。

总结

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。核心是牺牲空间换取时间。

242.有效的字母异位词

代码随想录:242.有效的字母异位词
Leetcode:242.有效的字母异位词

做题

直接用python的{}做题,需要对字典中没有的key进行添加,对字典中已有的key增加value。

看文章

使用数组

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        record = [0] * 26
        for i in s:
            #并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
            record[ord(i) - ord("a")] += 1
        for i in t:
            record[ord(i) - ord("a")] -= 1
        for i in range(26):
            if record[i] != 0:
                #record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return False
        return True

时间复杂度: O(n)
空间上因为定义是的一个常量大小的辅助数组,故空间复杂度: O(1)

使用defaultdict

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        from collections import defaultdict
        
        s_dict = defaultdict(int)
        t_dict = defaultdict(int)
        for x in s:
            s_dict[x] += 1
        
        for x in t:
            t_dict[x] += 1
        return s_dict == t_dict

使用counter

class Solution(object):
    def isAnagram(self, s: str, t: str) -> bool:
        from collections import Counter
        a_count = Counter(s)
        b_count = Counter(t)
        return a_count == b_count

349. 两个数组的交集

代码随想录:349. 两个数组的交集
Leetcode:349. 两个数组的交集

做题

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        a = set()
        res = set()
        for num in nums1:
            a.add(num)
        for num in nums2:
            if num in a:
                res.add(num)
        return list(res)

时间复杂度: O(n + m) m 是最后要把set转成vector
空间复杂度: O(n)

看文章

使用字典和集合

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
    # 使用哈希表存储一个数组中的所有元素
        table = {}
        for num in nums1:
            table[num] = table.get(num, 0) + 1
        
        # 使用集合存储结果
        res = set()
        for num in nums2:
            if num in table:
                res.add(num)
                del table[num]
        
        return list(res)

使用数组

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        count1 = [0]*1001
        count2 = [0]*1001
        result = []
        for i in range(len(nums1)):
            count1[nums1[i]]+=1
        for j in range(len(nums2)):
            count2[nums2[j]]+=1
        for k in range(1001):
            if count1[k]*count2[k]>0:
                result.append(k)
        return result

为什么使用数组?

答:直接使用set不仅占用空间比数组大,而且速度要比数组慢,set把数值映射到key上都要做hash计算的。在数据量大的情况,set会比数组慢很多,速度差距是很明显的。

使用集合

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return list(set(nums1) & set(nums2))

202. 快乐数

代码随想录:202. 快乐数
Leetcode:202. 快乐数

做题

class Solution:
    def isHappy(self, n: int) -> bool:
        a = set()
        cur = n
        a.add(cur)
        while True:
            cur_str = str(cur)
            cur = 0
            for i in cur_str:
                cur += int(i) ** 2
            if cur == 1:
                return True
            elif cur in a:
                return False
            else:
                a.add(cur)

将数字转成字符串,然后计算平方和,但int和str的互转可能会影响速度。

看文章

代码随想录的解法很多,也有用int和str互转的方法,下面是不用互转的方法。其余解法见代码随想录。

class Solution:
    def isHappy(self, n: int) -> bool:        
        record = set()

        while True:
            n = self.get_sum(n)
            if n == 1:
                return True
            
            # 如果中间结果重复出现,说明陷入死循环了,该数不是快乐数
            if n in record:
                return False
            else:
                record.add(n)

    def get_sum(self,n: int) -> int: 
        new_num = 0
        while n:
            n, r = divmod(n, 10)
            new_num += r ** 2
        return new_num

时间复杂度: O(logn)
空间复杂度: O(logn)

1. 两数之和

代码随想录:1. 两数之和
Leetcode:1. 两数之和

做题

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        a = {}
        size = len(nums)
        for i in range(size):
            a[nums[i]] = i 
        for i in range(size):
            if (target - nums[i]) in a and i != a[target - nums[i]]:
                return [i, a[target - nums[i]]]

时间复杂度: O(n)
空间复杂度: O(n)

看文章

代码随想录的解法很多。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        records = dict()

        for index, value in enumerate(nums):  
            if target - value in records:   # 遍历当前元素,并在map中寻找是否有匹配的key
                return [records[target- value], index]
            records[value] = index    # 如果没找到匹配对,就把访问过的元素和下标加入到map中
        return []

没找到匹配对,可以将访问过的加入map或set,提高效率。

以往忽略的知识点小结

  • 可以用ord()得出字母的编码,通过ord() - ord(‘a’)获得相对编码
  • 可以用&求set的交集
  • 可以用while n: n, r = divmod(n, 10)求n每个位置上的数

个人体会

完成时间:3h。
心得:补做昨天的题,难度还好;补充哈希表基础知识、补充ord()、divmod()等基础函数。

  • 19
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值