赎金信

标签: 哈希表 字符串 计数

难度: Easy

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = "a", magazine = "b"
输出:false

示例 2:

输入:ransomNote = "aa", magazine = "ab"
输出:false

示例 3:

输入:ransomNote = "aa", magazine = "aab"
输出:true

提示:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNotemagazine 由小写英文字母组成

Submission

运行时间: 20 ms

内存: 16.5 MB

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        r_set = set(ransomNote)
        r_list = list(r_set)
        for char in r_list:
            if char  not in magazine or ransomNote.count(char) > magazine.count(char):
                return False
        return True

Explain

该题解的思路是:首先用set去重获得ransomNote中的所有不重复字符,然后遍历这些字符,检查每个字符是否在magazine中出现,并且在ransomNote中出现的次数是否小于等于在magazine中出现的次数。如果检查通过,则返回True,否则返回False。

时间复杂度: O(mn)

空间复杂度: O(m)

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        # 获取ransomNote中不重复字符的集合
        r_set = set(ransomNote)
        # 将集合转换为列表
        r_list = list(r_set)
        # 遍历ransomNote中的不重复字符
        for char in r_list:
            # 检查字符是否在magazine中出现,且在ransomNote中出现的次数是否小于等于在magazine中出现的次数
            if char not in magazine or ransomNote.count(char) > magazine.count(char):
                return False
        return True

Explore

题解中选择先去重是为了减少不必要的重复检查。如果直接遍历ransomNote字符串,对于每个字符都会重复计算其在ransomNote和magazine中的出现次数,尤其是对于重复字符,这将导致不必要的性能浪费。通过去重,可以确保每个字符只被检查一次,从而提高效率。

将set转换为list这一步骤在本题中不是必须的,因为遍历set和遍历list的效率在这种情况下差别不大。set本身已经提供了必要的不重复性质和可遍历性。转换为list主要是为了在某些情况下需要对元素进行排序或其他特定操作时使用,但在这个算法中并不需要这些操作,因此这一步骤可以省略以优化性能。

在题解的方法中,每次检查一个字符时调用count函数将会对整个字符串进行遍历,这导致算法的时间复杂度较高。一个更高效的方法是首先使用哈希表(如Python中的字典)来统计ransomNote和magazine中每个字符的出现次数。这样,每个字符的出现次数只计算一次,之后可以直接从字典中获取,大大提高效率。

在题解中,如果magazine字符串很长,那么每次调用count函数都将遍历整个magazine字符串,这会导致算法效率降低。一个更优的处理方式是先统计magazine中每个字符的出现次数存入字典,然后遍历ransomNote中的字符,直接从字典中读取次数进行比较。这样可以避免重复遍历长字符串,特别是当magazine很长时,能显著提高效率。