算法训练Day6 | LeetCode:242. 有效的字母异位词(数组作哈希表);349. 两个数组的交集(Set作哈希表);202.快乐数 (Set作哈希表);1. 两数之和(Map作哈希表)

这篇博客主要讲解了使用哈希表解决LeetCode中的四道题目:242. 有效的字母异位词、349. 两个数组的交集、202. 快乐数以及1. 两数之和。博主探讨了数组、Set和Map作为哈希表在不同场景下的应用,分析了各种方法的思路、代码实现、复杂度和思考点,强调了哈希表在快速查找和去重中的重要作用。
摘要由CSDN通过智能技术生成

目录

LeetCode242. 有效的字母异位词

方法:数组作哈希表

1. 思路

2. 代码实现 

3. 复杂度分析

4. 思考

Leetcode349. 两个数组的交集 

方法一:用Set作HashMap

1. 思路

 2. 代码实现

3. 复杂度分析

4. 思考

方法二:用数组作HashMap

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考

Leetcode202.快乐数 

方法: Set用作HashMap

1. 思路

2. 代码实现

3. 复杂度分析

4. 思考

Leetcode1. 两数之和

 方法: Map作哈希表

1. 思路

 2. 代码实现

3. 复杂度分析

4. 思考


LeetCode242. 有效的字母异位词

链接:242. 有效的字母异位词 - 力扣(LeetCode)

 核心点:感受到 数组 用来做哈希表 给我们带来的便利。

先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。

暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。

方法:数组作哈希表

1. 思路

先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。

暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。

数组其实就是一个简单哈希表,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。

需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。

Example:为了方便举例,判断一下字符串s= "aee", t = "eae"。

定义一个数组叫做record用来上记录字符串s里字符出现的次数。

需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。

最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

2. 代码实现 

class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        # 数组作哈希表,记录元素出现的频率
        record = [0]*26
        # 遍历字符串S,在每个对应位置上+1
        for item in s:
            index = ord(item) - ord("a")
            record[index] += 1
        # 遍历字符串T,在每个对应位置上-1
        for item in t:
            index = ord(item) - ord("a")
            record[index] -= 1
        # 看看最后的哈希表是不是元素全为0
        for i in range(0,26):
            if record[i] != 0: 
                return False
        return True

3. 复杂度分析

因为要分别遍历长度为N的字符串s和t,所以时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。

4. 思考

(1)常用的三种哈希表有数组、set和map,当哈希表比较小并且范围确定的时候,用数组;当哈希表范围比较大而且不确定的时候,用set;当有key-value的映射关系的时候,用map。

(2)在C++ 中,直接用字母减字母的话,编译器会自动用字母的ASCII码计算,但是在Python中要用ord(“a”),我们并不用搞清楚ASCII码究竟是多少,只用知道这26个字母是连续的,然后减去”a”的ASCII码,算出一个相对位置就可以了。

(3)还有另一种做法是,把两个字符串分别用两个数组统计,然后再比较两个数组是否一样。

(4)这道题是数组在Hash Map中的经典应用。

(5)思考:我们遇到要快速判断元素是否出现在集合里的时候,要考虑哈希法。

(6)数组就是简单的哈希表,但是数组的大小可不是无限开辟的。

本题学习时间:55分钟


Leetcode349. 两个数组的交集 

链接:  349. 两个数组的交集 - 力扣(LeetCode)

 这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。

思考:

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

方法一:用Set作HashMap

1. 思路

本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,我们可以先忽略这个条件,尝试去用set解决这道题目。

数据结构的选择?要不要用数组作为Hash table?为什么要用set作哈希表?

用数组来做哈希表是不错的选择,例如,前一道题:有效的字母异位词

但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。

而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。

而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。所以我们打算选择set。

用set的思路如下:

  1. 首先,定义一个set哈希表,称为result,存放之后要返回的结果,之所以用set是因为它可以在insert元素的时候就自动去重;
  2. 把nums1中的元素放进另一个set哈希表中(会做去重操作),定义为num1_set;
  3. 遍历nums2中的元素,然后再nums1_set这个哈希表中找有没有出现,如果找到了的话,就把它存到result中去;
  4. 遍历结束之后,将result转换为list返回

 2. 代码实现

# 把set用作hashMap
# time:O(N);space:O(N)
class Solution(object):
    def intersection(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        # 保存结果的result初始化
        result = set()
        # 将nums1中的元素存入set中
        nums1_set = set(nums1)
        # 遍历nums2,和nums1_set比较,如果存在,就加进result
        for item in nums2:
            if item in nums1_set:
                result.add(item)
        return list(result)

3. 复杂度分析

时间复杂度和空间复杂度都是O(N)。

将nums1中的元素存入set数据结构中,就是O(N)的时间复杂度,然后遍历num2中的元素一个个比较,又是O(N)的时间复杂度,最后把result转换成list,也是O(N)的时间复杂度,所以总体来说time complexity = O(N);空间上创建了两个set和一个list,长度都是O(N)数量级的,所以space complexity = O(N)。

4. 思考

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
给定一个整数组 nums 和一个目标值 target,要求在数组中找出两个的和等于目标值,并返回这两个的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个的和是否等于目标值。如果等于目标值,则返回这两个的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值