算法训练营Day05

1. 242-有效的字母异位词

力扣题目链接(opens new window)

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

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

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

说明: 你可以假设字符串只包含小写字母

哈希表在数组中的应用

  • 字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25

  • 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了, 差值是从0到25

  • 不需要分别统计s和t中各字符,记录一个+1,另一个-1,最后判断是否全为0,更简便

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

    class Solution:
        def isAnagram(self, s: str, t: str) -> bool:
            #使用数组哈希表
            record = [0] * 26  # 定义0数组来记录字符出现次数
            for i in s:
                record[ord(i) - ord('a')] += 1 #计算s中各字符相对’a'的ASCII差值,然后记录+1
            for i in t:
                record[ord(i) - ord('a')] -= 1  #计算t中的,记录-1
    ​
            for i in record:
                if i != 0:
                    return False
            return True
  • 暴力解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。

    Python写法二(没有使用数组作为哈希表,只是介绍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
    Python写法三(没有使用数组作为哈希表,只是介绍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

2. 349-两个数组的交集

如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费!

力扣题目链接(opens new window)

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

349. 两个数组的交集

说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。

这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。

注意题目特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序

这道题用暴力的解法时间复杂度是O(n^2)

关于set,C++ 给提供了如下三种可用的数据结构:

  • std::set

  • std::multiset

  • std::unordered_set

std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        #哈希表 key 为 nums1 数组中的数,value 为值
        hash = {}
        res = []
​
        for i in nums1:
            if not hash.get(i): #限定了key=i value无值时
                hash[i] = 1 
        
        for j in nums2:
            if hash.get(j): #如果nums2中的数在hash存在
                res.append(j) #对应的数存入res列表
                hash[j] = 0 #对应value置为0
        
        return 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

(版本三) 使用集合

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

3. 202-快乐数

力扣题目链接(opens new window)

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

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

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

示例:

输入:19 输出:true 解释: 1^2 + 9^2 = 82 8^2 + 2^2 = 68 6^2 + 8^2 = 100 1^2 + 0^2 + 0^2 = 1

class Solution:
    def isHappy(self, n: int) -> bool:
        #使用集合
        record = set() #记录出现过的数
​
        while n != 1:
            n = sum(int(i) ** 2 for i in str(n)) #计算平方和
            if n in record: #若出现过,则进入无限循环
                return False
            else:
                record.add(n) #没出现过,则记录
        return True

4. 1-两数之和

力扣题目链接(opens new window)

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

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

示例:

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

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

所以返回 [0, 1]

本题重点明确:

  • 为什么使用哈希表

    当我们需要查询一个元素是否在集合里,就要第一时间想到哈希法。本题需要一个集合来存放遍历过的元素,并在后续需要查询这个集合是否有某元素。

  • 为什么使用map

    本题不仅需要查询集合中是否有某元素,且需要该元素的下标。所以key存放元素,value存放下标。

  • map的作用:存放遍历过的元素

为什么不使用数组或set:

  • 数组的大小是受限制的,如果元素很少,而哈希值太大会造成内存空间的浪费。

  • set是一个集合,里面放的元素只能是一个key,而本题不仅要查询某元素是否存在,且需要下标。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        #使用字典
        record = dict()
​
        for index, num in enumerate(nums): #key存放元素num,value存放下标index
            if target - num in record: #判断是否互补元素是否在record
                return [record[target-num], index] #若有,返回两个下标
            record[num] = index  #若没有,存放进字典
​
        return []
  • 时间复杂度: O(n)

  • 空间复杂度: O(n)

     

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值