代码随想录算法训练营第六天|242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

242.有效的字母异位词

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

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

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

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

首先排除暴力法,思路太简单不多赘述。

思路首先想到哈希,对应字母出现一次,则对应的哈希表位置+=1,由于本次题目限制在了小写字母,所以取值范围就是1-26,范围确定可以使用数组,如果不确定数的范围,无法使用数组,而是需要使用set,本题使用数组。

由于用数组需要用到数字,小写字母对应数组我们可以想到ASCII码,每个字母的ASCII码减去‘a’的ASCII码恰好就是英文字母表的对应顺序,一一对应。

代码实现如下:

class Solution:

    def isAnagram(self, s: str, t: str) -> bool:

        # 确认范围是'a'到'z',使用数组

        nums = [0] * 26

        for i in s:

            nums[ord(i)-ord('a')] += 1

        for i in t:

            nums[ord(i)-ord('a')] -= 1

       

        for i in range(26):

            if nums[i] != 0:

                return False

        return True

另外记录defaultdict和counter的用法,代码随想录提供的代码如下:

defaultdict

defaultdict 是 dict 的一个子类,它提供了一个默认值的机制,当访问字典中不存在的键时,会自动创建该键,并将其值设置为默认值。

Counter

Counter 是一个字典子类,用于计数可哈希对象。它是一个集合,元素的数目由字典的值给出。

总结

  • defaultdict 允许你为字典中不存在的键提供一个默认值。
  • Counter 是一个专门用于计数的字典,它提供了方便的方法来添加和更新计数。

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

349. 两个数组的交集

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

349. 两个数组的交集

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

思路很明确,只是不熟悉python提供的几个集合类用法,具体思路就是判断数组2里的数字是否在数组1中出现过,如果出现过就存储在result数组中,同时确保相同数字在result数组中只出现一次,如果判断在result数组中已有,则不存入。

代码实现如下:

class Solution:

    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:

        #num = set()                   # 后面发现使用set好像有点多余,去掉了依然通过

        result = []

        #for i in nums1:

        #    num.add(i)

        for i in nums2:

            if i in nums1 and i not in result:

                result.append(i)

        return result

使用字典和集合的方法如下,顺便学习一下字典和集合的用法:

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)
  1. 创建哈希表:首先,代码通过一个循环遍历 nums1 数组,使用一个字典 table 来存储 nums1 中的每个元素及其出现的次数。这里使用 table.get(num, 0) 来获取字典中 num 的当前值,如果 num 不在字典中,则返回默认值 0。然后将这个值加一,表示 num 出现了一次。
  2. 初始化结果集合:使用一个集合 res 来存储最终的交集结果。集合自动去重,因此如果 nums1 和 nums2 中有重复的元素,它们在结果中也只会被计算一次。
  3. 遍历第二个数组:代码通过另一个循环遍历 nums2 数组。对于 nums2 中的每个元素 num,如果它存在于 table 字典中(即 num 也在 nums1 中),则将其添加到结果集合 res 中,并从 table 中删除该元素。这样做是为了确保每个元素在结果中只出现一次,即使它在 nums1 中出现多次。
  4. 返回结果:最后,将结果集合 res 转换回列表,并返回这个列表。

这段代码的效率相对较高,因为它只需要遍历两个数组各一次,并且使用哈希表和集合的查找和插入操作的时间复杂度通常是 O(1)。因此,整个算法的时间复杂度是 O(n + m),其中 n 和 m 分别是 nums1 和 nums2 的长度。

使用数组的方法在此忽略了,另外再学习一下集合的用法,使用set1&set2方法取交集,使得代码十分精简:

class Solution:

    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:

        return list(set(nums1) & set(nums2))
  1. 转换为集合:首先,将 nums1 和 nums2 转换为集合 set(nums1) 和 set(nums2)。集合是一个无序的不重复元素集,自动去除了数组中的重复元素。
  2. 集合交集操作:使用 & 运算符来获取两个集合的交集。在Python中,& 运算符用于计算两个集合的交集,即同时存在于两个集合中的元素。
  3. 返回结果:最后,将得到的交集集合转换回列表,并返回这个列表。

这段代码的优点是简洁易读,且利用了Python的集合操作,使得代码更加直观。其时间复杂度主要由集合的创建和交集操作决定,通常也是 O(n + m),其中 n 和 m 分别是 nums1 和 nums2 的长度。

第202题. 快乐数

编写一个算法来判断一个数 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

这道题思路为:首先判断数字是否为1,为1直接返回True。

其次直接进入循环,对每一位都进行平方加和处理,只要得到的结果res不为1就循环执行,问题在于这个过程有可能会无限循环下去,因为res可能永远不等于1,这说明res有可能会重复出现得到同样的数字,所以需要一个集合set来记录出现过的res,当出现重复res的时候肯定能够判断不是快乐数,此时直接返回False

这道题思路挺早想出来,但是程序实现上一直卡bug,问题就在于对数字的处理不是特别的熟练,应该学会用函数单独分出来处理会有助于处理过程。同时在代码中,忘记了python中/10是不会向下取整的,是得到一个浮点数。

如果你想要进行向下取整或向上取整,可以使用以下方法:

  1. 向下取整:可以使用 // 运算符,它执行的是整数除法,结果总是向下取整到最接近的整数。

python

result = 9 // 10

print(result)  # 输出: 0

  1. 向上取整:Python没有内置的向上取整运算符,但可以通过一些方法实现。一个常用的方法是将除法结果加上一个特定的值后再进行向下取整。

python复制

result = (9 + 9) // 10

print(result)  # 输出: 1

因此要结束循环应该是使用//10或者设置循环条件为>1

代码实现如下:

class Solution:

    def isHappy(self, n: int) -> bool:

        if n == 1:

            return True

        else:

            new_n = n

        mark = set()



        while new_n != 1:

            res = 0

            while new_n > 0:

                res += (new_n%10)**2

                #new_n = new_n / 10

                new_n = new_n // 10         # 这里需要注意用//10来向下取整,不然会死循环

           

            if res == 1:

                return True

            else:

                if res in mark:

                    return False

                else:

                    mark.add(res)

                    new_n = res

       

在处理各位数平方和的时候可以考虑使用以下函数

divmod(a, b)

参数

  • a:被除数。
  • b:除数。

返回值

  • 返回一个包含两个元素的元组 (quotient, remainder),其中 quotient 是商,remainder 是余数。

另外记录学习其他代码实现方式:

最直接的思路,直接复述题目的计算过程,方法是先转换为str,然后再对每一位转换为int进行运算:

class Solution:

   def isHappy(self, n: int) -> bool:

       record = set()

       while n not in record:

           record.add(n)

           new_num = 0

           n_str = str(n)

           for i in n_str:

               new_num+=int(i)**2

           if new_num==1: return True

           else: n = new_num

       return False

集合+精简:

class Solution:

   def isHappy(self, n: int) -> bool:

       seen = set()

       while n != 1:

           n = sum(int(i) ** 2 for i in str(n))

           if n in seen:

               return False

           seen.add(n)

       return True


1. 两数之和

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

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

示例:

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

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

所以返回 [0, 1]

最直接的思路,暴力法复杂度肯定是n²,直接排除。

自己的思路:由于是两数加和等于target,所以确定了第一个数n1的时候,n2的具体数值其实已经确定是target-n1,所以我只需要在剩下的数组元素中寻找是否存在n2即可,如果没有就令n1等于下个数字重复以上过程。(一开始以为只需要输出两个数,但后面才发现需要输出的是两个下标,所以时间非常长,实现的应该不对。后来其实想到要用字典实现,但因为字典用法还是不熟悉,感觉把时间浪费在不熟悉没怎么用过的地方没啥意义,就直接看规范代码了)

代码实现如下:

class Solution:

    def twoSum(self, nums: List[int], target: int) -> List[int]:

        length = len(nums)

        for i in range(length):

            n1 = nums[i]

            n2 = target-n1

            j = i+1

            while j<length:

                if nums[j] == n2:

                    return [i, j]

                else:

                    j += 1

        return None

       

使用字典:我一开始的疑惑在于相同元素加和的时候,另外一个元素匹配到自己的话怎么办,没想到可以把遍历过的元素再放进字典中,这样第一次匹配到后面那个元素的时候,就必然会匹配到前面的那个元素,这个思路对自己很有启发。

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 []

在Python中,enumerate() 是一个内置函数,用于将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列,同时列出数据和数据下标。这使得在遍历可迭代对象时,可以同时获取到元素的索引和值。

语法

python

enumerate(iterable, start=0)

参数

  • iterable:一个可迭代对象,如列表、元组、字符串等。
  • start(可选):计数开始的索引,默认为0。如果指定了 start 参数,那么索引将从这个值开始。

返回值

enumerate() 返回一个枚举对象,该对象可以被用来创建索引序列。通常,我们使用循环来遍历这个枚举对象。

所以for index, value in enumerate(nums):可以返回对应的index和value

使用集合:

class Solution:

    def twoSum(self, nums: List[int], target: int) -> List[int]:

        #创建一个集合来存储我们目前看到的数字

        seen = set()            

        for i, num in enumerate(nums):

            complement = target - num

            if complement in seen:

                return [nums.index(complement), i]

            seen.add(num)

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值