(补)代码随想录算法训练有营DAY6|Leetcode 242、349、202、1

文章链接:代码随想录

哈希表理论基础 + 242.有效的字母异位词 + 349. 两个数组的交集 + 202.快乐数 + 1. 两数之和

视频链接:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词_哔哩哔哩_bilibili

实际写代码过程中已经多次用过哈希表思想了,但没有过系统学习,在此重新学习一遍。

引自代码随想录:当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。

242.有效的字母异位词

状态:先看视频,学习解题思路,再自己复现代码

思路:用哈希表的数组结构,做减法

        1)统计第一个字符串s的字母出现情况:26个小写字母ASCII码与字母 'a' ASCII码的差值对应hashlist各元素的下标,下标范围[0, 25]

        2)在统计好的hashlist上做减法:字符串t每出现一次与s相同的字母,hashlist中对应的元素减1

        3)若最终的hashlist为全0,则s 和 t是有效的字母异位词

总结:

1. 使用哈希表时,常用的3种数据结构有:

        1)数组:适用于数据范围可控(或较小)的情况

        2)集合set:相比数组,更适合于数组范围较大、较分散的情况

        3)  映射map:适用于哈希值特别分散、跨度大的情况

2. Python中,要用ord()函数来获取对应的 ASCII 数值,不支持字符直接相减

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

    空间复杂度: O(1)

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        hashlist = [0] * 26
        for i in s:
            hashlist[ord(i) - ord('a')] += 1
        for i in t:
            hashlist[ord(i) - ord('a')] -= 1
        for i in range(len(hashlist)):
            if hashlist[i] != 0:
                return False
        return True

349. 两个数组的交集

状态:直接使用python中set()的自带功能,一行搞定;但还可以用数组方式解决

思路:看过视频和文章讲解,除了上述两种方法,还有字典+集合方法

        1)方法一:直接使用python中set()的自带功能找交集,set() & set()或set().intersection(set())

        2)方法二:使用数组,两个for循环分别记录两个nums的元素出现次数,再对比是否有交集

        3)方法三:使用字典+集合方法,先用dict存第一个数组的所有元素,再用一个for循环遍历第二个数组,查看其元素是否存在于dict中,同时用set存储交集。注意:set存过的元素要从dict()中删除,减少重复操作

总结:

1. Python的set()是无序的不重复元素序列,自带功能挺强大的,可以合理利用

2. 方法二对比是否有交集可以用不同方式:if count1[k] and count2[k] 或者 if count1[k] * count2[k] > 0 均可

# set()自带功能
class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        # return list(set(nums1) & set(nums2))
        return list(set(nums1).intersection(set(nums2)))
# 方法二:使用数组
class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        count1, count2 = [0]*1001, [0]*1001
        result = []
        for i in nums1:
            count1[i] += 1
        for i in nums2:
            count2[i] += 1
        for k in range(len(count1)):
            if count1[k] and count2[k]:  # 也可用 count1[k] * count2[k] > 0
                result.append(k)
        return result

202.快乐数

状态:先看文章讲解和示例代码,再自己复现,但过程中有问题出现

思路:

抓住题目中的重点:题干说了会 无限循环,也就是说求和的过程中,sum会重复出现,即判断一个元素是否出现在集合里;求和过程就是数值不断对10取模得余数再求平方和

总结:

1. 第一次看题,没有理解“无限循环”, 看过题解后才理解为什么要用哈希法

2. 看过python示例代码,但是复现过程中发现自己还是忽略了一些逻辑细节问题:解法一里的传入参数和判断变量必须保持一致(均为n),不能用新变量替换(错误写法放在下面)。因为n是不断更新的,需要同时作为判断条件和循环语遍历的范围来使用

3. 另一种解法,使用集合,并且使用str(n)将int型数值转换为字符串,方便进行求和操作,和第一个解法相比更简洁快速,但是和代码随想录的版本二写法相比还是稍显复杂

4. 时间复杂度: O(logn)

    空间复杂度: O(logn)

错误代码:

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

        while True:
            # 不能定义新变量sums, 而应与传入参数n保持一致,
            # 否则在下一次循环中,求和时本应传入此刻的sums值,却依然传入的是n
            # 如果要写为sums = self.get_sum(sums),则函数isHappy()的传入参数应改为sum:int
            sums = self.get_sum(n)  
            if sums == 1:
                return True

            if sums in record:
                return False
            else:
                record.add(sums)

    def get_sum(self, num:int) -> int: # 传入参数应为n
        new_sum = 0
        while num:  # 死循环,传入参数num一直不变
            n, r = divmod(num, 10) # 同样的,num要改为n
            new_sum += r **2
        return new_sum

正确代码:

# 解法一(与错误代码作对比)
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_sum = 0
        while n:
            n, r = divmod(n, 10)
            new_sum += r **2
        return new_sum
# 解法二
class Solution:
    def isHappy(self, n: int) -> bool:
        record = set()
        while True:
            new_sum = 0
            n_str = str(n)
            for i in n_str:
                new_sum += int(i) ** 2
            n = new_sum
            if n == 1:
                return True
            if n in record:
                return False
            else:
                record.add(n)
            

1. 两数之和

状态:先看视频,再自己写代码

思路:

1. 暴力解法:两个for循环,两两元素依次相加,直到找到和等于target的两个元素

2. 哈希法:使用一个dict()存储遍历过的元素(同时存数值和下标),在遍历数组的同时,从dict()中查找是否存在某元素等于(target - 当前所指向的元素)

总结:

1. 理解4个重点问题:

  • 为什么会想到用哈希表 
    • 按照思路2,要在已存储的集合中查找是否存在符合条件的某元素,考虑用哈希法
  • 哈希表为什么用map
    • 题目要求返回元素对应的下标。在查找元素时,首先要利用元素的数值判断是否符合条件,如符合条件,则需要返回其下标,所以元素的数值value和下标key要同时存储在集合中
  • 本题map是用来存什么的 
    • 存储已遍历过的元素
  • map中的key和value用来存什么的
    • key对应元素的数值,value对应元素的下标

2. Python 中的dict() 与C++的map()相似,dict()的功能也很强大,要合理利用

3. Python 中的enumerate()函数将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列,返回的结果是一个元组,包含索引和对应的元素。这个函数常用于循环迭代时,需要同时获取元素和其对应的索引。

4. 哈希法  时间复杂度: O(n), 空间复杂度: O(n)

# 暴力解法
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):
                if nums[i] + nums[j] == target:
                    return [i,j]
# 哈希法
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        record = dict()

        for k, v in enumerate(nums):
            if target - v in record:
                return [record[target - v], k]
            record[v] = k
        return []

第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值