Skip to content

383.赎金信

难度:简单

给你两个字符串: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 由小写英文字母组成

解题思路

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

record 数组的大小为 26 就可以了,初始化为 0,因为字符 a 到字符 z 的 ASCII 也是 26 个连续的数值。

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

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

之后检查字符串 ransomNote 中是否出现了这些字符,在遍历字符串 ransomNote 的时候,先判断 record 数组中对应索引处的值是否大于 0,如果不大于 0,说明 ransomNote 中出现了 magazine 中没有或者不足的字符,此时返回 false。

如果索引处的值大于 0,则只需要对 ransomNote[i] - ‘a’ 所在的元素做 - 1 操作即可。

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

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

注意一开始就对比一下字符串长度,可以直接排除一些错误情况。

我的代码

java
public boolean canConstruct(String ransomNote, String magazine) {
    if (magazine.length() < ransomNote.length()) {
        return false;
    }
    int[] record = new int[26];

    for (int i = 0; i < magazine.length(); i++) {
        record[magazine.charAt(i) - 'a']++;// 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
    }

    for (int i = 0; i < ransomNote.length(); i++) {
        if (record[ransomNote.charAt(i) - 'a'] > 0) {
            record[ransomNote.charAt(i) - 'a']--;
        } else {
            return false;
        }
    }
    return true;
}

时间复杂度:O(n)

空间复杂度:O(1),因为定义是的一个常量大小的辅助数组

总结

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

注意一开始就对比一下字符串长度,可以直接排除一些错误情况。

为什么要用数组,而不用 hashMap?

其实在本题的情况下,使用 hashMap 的空间消耗要比数组大一些的,因为 hashMap 要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!