Day 06 算法学习|哈希表01

题目 242. Valid Anagram

题目链接

题目描述:

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1: 输入: s = "anagram", t = "nagaram" 输出: true

示例 2: 输入: s = "rat", t = "car" 输出: false

解题思路:

本题主要在于解决,判断两个词组是否由相同的字母组成。首先可以判断,两个词组不一样长的话就肯定不同, 然后在长度相同的情况下进行判断。如果用暴力解法,那么肯定会造成复杂度升高,所以才用hash表的方式解决。 

首先创造一个长度为26,每个元素都为0的哈希表,代表26个字母出现的频次。当我们有一个词组,想要判断它在hash表中的各个字母出现频次的时候,采用ascall方法。在python中,ord('a')表示字母a的ascall码值,如果一个词组为“dog”,我们要找各个单词的频次的时候,利用

ord("d")-ord("a")得到字母d在哈希表中的index,然后将对应index的数值+1,字母d在hash表对应的值就加1.

回到本题,我们要判断两个词组是否相等,就不用分别创建两个hash表来比较了,在得到第一个词组的hash表的时候,将第二个词组直接在上面操作,不过区别在于对应频次减1,如果最后hash表全为0,那么这两个词组就是异位词。

代码:

注意⚠️

hash_0不能直接等于hash,因为实际上是将hash_0设置为了对hash列表的引用。这意味着hash_0hash指向同一个列表对象,它们共享相同的内存空间。因此,当对hash进行修改时,hash_0也会同时受到影响。

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        #define a hashtable record
        hash=[0]*26
        hash_0=[0]*26
        if len(s)!=len(t):
            return False
        else:
            for i in s:
                hash[ord(i)-ord("a")]+=1
            for j in t:
                hash[ord(j)-ord("a")]-=1
            if hash==hash_0:
                return True
            else:
                False




        


复杂度:

时间复杂度:

  1. 创建两个长度为26的哈希表,需要O(1)的时间复杂度。
  2. 检查两个词组的长度是否相等,需要O(1)的时间复杂度。
  3. 遍历第一个词组,对哈希表进行操作,需要O(n)的时间复杂度,其中n是第一个词组的长度。
  4. 遍历第二个词组,对哈希表进行操作,同样需要O(n)的时间复杂度。
  5. 比较哈希表是否全为0,需要O(1)的时间复杂度。

综上所述,代码的时间复杂度是O(n),其中n是词组的长度。

空间复杂度: 代码使用了两个长度为26的哈希表来记录字母的频次,因此需要额外的空间来存储这两个哈希表。哈希表的长度是固定的,所以空间复杂度是O(1)。

综上所述,代码的空间复杂度是O(1)。

题目 349. 两个数组的交集

题目链接

题目描述:

给定两个数组,编写一个函数来计算它们的交集

解题思路:

本题在于求出两个集合相同的元素,而且结果必须是unique的。这道题采用hash  set方法,先把第第一个list的hash set求出来,这种情况下所有元素都是unique的,然后查看第二个list中的元素是否在hash set中出现过,特别注意,在进行查询工作时, 以下代码的顺序不能错,如果写成for i in nums2 , if i in set_1,那么就违背了所有相交元素都是唯一的的限制。

for i in set_1:

        if i in nums2:

                res.append(i)

代码:

创建set直接用set(nums),不用写个for循环。

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        #hashtable(list,map,set),元素出现
        #如果数值很大就不用list,浪费存储空间,本题用set(python dict)
        #generate a hashtable for nums1
        set_1 = set(nums1)
        res = []
        #found element in nums2 in nums1_dict or not
        for i in set_1:
            if i in nums2:
                res.append(i)
        return res

复杂度:

时间复杂度:

  1. 创建哈希集合 set_1,需要将 nums1 中的元素逐个添加到集合中,这需要 O(n1) 的时间复杂度,其中 n1 是 nums1 的长度。
  2. 遍历 set_1,对其中的元素进行查询操作,检查其是否存在于 nums2 中,这需要 O(n2) 的时间复杂度,其中 n2 是 nums2 的长度。

综上所述,代码的时间复杂度是 O(n1 + n2),其中 n1 是 nums1 的长度,n2 是 nums2 的长度。

空间复杂度:

  1. 创建了一个哈希集合 set_1 来存储 nums1 中的元素,这需要 O(n1) 的空间复杂度,其中 n1 是 nums1 的长度。
  2. 创建了一个结果列表 res 来存储相交的元素,其最大长度不会超过 nums1nums2 的长度的较小值。因此,结果列表的空间复杂度为 O(min(n1, n2))

题目 202. Happy Number

题目链接

题目描述:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为  1,那么这个数就是快乐数。

如果 n 是快乐数就返回 True ;不是,则返回 False 。

解题思路:

本题在于一直求解各个数字的平方和是否有1出现,如果没有说明进入一个循环了。让我们知道出现一和是否进入循环就用hashtable,但在这之前我们要写一个function用来计算一个数的各位平方和,,字符串方法和算术方法。虽然字符串方法可能更直观,但算术方法在性能上可能更优,因为它避免了数字和字符串之间的转换。

def getSumOfSquares(num):
            total_sum = 0
            while num > 0:
                #求解个位数
                digit = num % 10
                total_sum += digit * digit
#求解除了个位数之外的数
                num //= 10
            return total_sum

比如说135, 135%10=5,135//=10:13, 13%10=3,13//=10:1

然后,我们使用一个哈希集合(hash set)来跟踪我们已经见过的数字。在每次迭代中,我们都计算n的各位数字的平方和,并检查这个结果是否为1(表示n是一个快乐数)或者这个结果是否已经在我们的哈希集合中(表示我们已经进入了一个循环)。如果满足这两个条件中的任何一个,我们就退出循环。

最后,当我们退出循环时,我们检查n是否等于1。如果是,那么我们知道n是一个快乐数,函数返回真(true)。如果不是,那么我们知道n不是一个快乐数,因为我们已经进入了一个不包含1的循环,函数返回假(false)。

 seen = set()
        while n != 1 and n not in seen:
            seen.add(n)
            n = getSumOfSquares(n)
        return n == 1

代码:

解法一:

class Solution:
    def isHappy(self, n: int) -> bool:
        # Define a helper function to get the sum of the squares of the digits of a number
        def getSumOfSquares(num):
            total_sum = 0
            while num > 0:
                #求解个位数
                digit = num % 10
                total_sum += digit * digit
                #求解除了个位数之外的数
                num //= 10
            return total_sum


        # Use a set to store the sums we have already calculated
        seen = set()
        while n != 1 and n not in seen:
    # If the number is not 1 and we have not seen it before, add it to the set
            seen.add(n)
    # Get the sum of the squares of the digits
            n = getSumOfSquares(n)

        # If we end with 1, then n is a happy number
        return n == 1


解法二:

class Solution:
    def isHappy(self, n: int) -> bool:
        def getSumOfSquares(n):
            sum = 0
            # Convert the number to a string to iterate over its digits
            n = str(n)
            for digit in n:
                # Convert the digit back to an integer and add its square to the sum
                sum += int(digit)**2
            return sum
        
        # Use a list to keep track of the sums we have already seen
        hash_list = []
        
        while True:
            n = getSumOfSquares(n)
            if n == 1:
                # If the sum is 1, the number is happy
                return True
            elif n in hash_list:
                # If the sum is in our list, we have entered a cycle, so the number is not happy
                return False
            else:
                # If the sum is new, add it to our list and continue the loop
                hash_list.append(n)
        # This line is unnecessary because the function always returns before reaching it
        #return False

复杂度:

  1. 时间复杂度:O(log n)

    这个算法的时间复杂度可能并不直观。虽然我们在循环中进行了多次计算,但每次计算都会让数字n变小。因此,我们可以认为时间复杂度是O(log n)。这是一个很宽松的上界,实际的时间复杂度可能更低,因为我们通常很快就会达到1或者进入一个循环。

  2. 空间复杂度:O(log n)

    我们用一个集合来保存已经计算过的数字的平方和。在最坏的情况下,我们可能需要保存所有这些数字,因此空间复杂度是O(log n)。这是因为每次计算都会使数字n变小,所以我们最多需要log n步才能达到1或者进入一个循环。

题目:

1. Two Sum

题目链接

题目描述:

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

解题思路:

本题要找两个数字想加起来等于target,并且返回各自的下标。如果我们用暴力解法写两层for循环,那么就会有O(n^2)的复杂度,所以采用hash map的方法,找寻这个map里面是否存在target-val, 最开始的时候虽然hash map是空的,但是不能直接往里面加元素,需要直接先写决定条件,

如果我们先把 val 添加到哈希表中,那么在 val 等于 target - val 的情况下,我们就无法正确判断出这是满足条件的一个解。

举个例子,假设我们的 target 是 6,现在遍历到的 val 是 3,且这是数组中的第一个元素。此时 target - val 也是 3,如果我们在判断条件之前先把 val 添加到哈希表中,那么在执行判断条件 if target - val in hash.keys(): 时,会发现 target - val 已经在哈希表中,从而错误地认为我们找到了一个解,其实并没有。

所以,为了避免这种情况,我们需要先写判断条件,如果 target - val 在哈希表中,就返回对应的索引,否则再把 val 添加到哈希表中。这样就能保证我们的算法能正确地找到满足条件的两个数。

if target-val in hash.keys():

        return [hash[ target-val],index]

else:

        hash[val]=index

代码:

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        #hash map
        hash={}

        #查找target-val是否在hash中出现过,如果有则返回
        for index,val in enumerate(nums):
            if target-val in hash.keys():
                return [hash[ target-val],index] 
            else:
                hash[val]=index
            


复杂度:

  1. 时间复杂度:O(n)

这个算法只需要遍历一次数组。因为哈希表(在 Python 中为字典)的查找操作的平均时间复杂度接近 O(1),因此总的时间复杂度为 O(n)。

  1. 空间复杂度:O(n)

这个算法使用了一个哈希表来保存数组中的元素和对应的索引。在最坏的情况下,数组中的每个元素都会被存入哈希表,因此空间复杂度为 O(n)。

注意:尽管哈希表的查找操作的平均时间复杂度是 O(1),但在极端情况下(所有元素都哈希到同一个位置)可能会退化为 O(n)。然而,这种情况在实践中几乎不会发生,所以我们通常认为哈希表的查找操作的时间复杂度是 O(1)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值