哈希表7——赎金信

题目

力扣题目链接

https://leetcode.cn/problems/ransom-note/

题目说明

给你两个字符串: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 ≤ r a n s o m N o t e . l e n g t h , m a g a z i n e . l e n g t h ≤ 105 1 \leq ransomNote.length, magazine.length \leq 105 1ransomNote.length,magazine.length105
  • ransomNotemagazine 由小写英文字母组成
    通过次数198,496提交次数316,170

解题方法

方法一:字符统计

题目要求使用字符串 magazine 中的字符来构建新的字符串 ransomNote,且ransomNote 中的每个字符只能使用一次,只需要满足字符串 magazine中的每个英文字母 (’a’-’z’) 的统计次数都大于等于 ransomNote中相同字母的统计次数即可。

  • 如果字符串 magazine 的长度小于字符串 ransomNote 的长度,则我们可以肯定magazine无法构成 ransomNote,此时直接返回 false
  • 首先统计 magazine中每个英文字母 a 的次数 cnt[a],再遍历统计 \textit{ransomNote}ransomNote 中每个英文字母的次数,如果发现ransomNote 中存在某个英文字母 c 的统计次数大于 magazine中该字母统计次数 cnt[c],则此时我们直接返回 false

代码

python

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        if len(ransomNote) > len(magazine):
            return False
        return not collections.Counter(ransomNote) - collections.Counter(magazine)

C++

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        if (ransomNote.size() > magazine.size()) {
            return false;
        }
        vector<int> cnt(26);
        for (auto & c : magazine) {
            cnt[c - 'a']++;
        }
        for (auto & c : ransomNote) {
            cnt[c - 'a']--;
            if (cnt[c - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
};

复杂度分析

  • 时间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m 是字符串 ransomNote的长度,n 是字符串 magazine 的长度,我们只需要遍历两个字符一次即可。

  • 空间复杂度: O ( ∣ S ∣ ) O(|S|) O(S)S 是字符集,这道题中 S 为全部小写英语字母,因此 ∣ S ∣ = 26 |S| = 26 S=26

方法二:哈希表

因为题目所只有小写字母,那可以采用空间换取时间的哈希策略, 用一个长度为26的数组还记录magazine里字母出现的次数。

然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。

依然是数组在哈希法中的应用。

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

代码如下:

C++

// 时间复杂度: O(n)
// 空间复杂度:O(1)
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        //add
        if (ransomNote.size() > magazine.size()) {
            return false;
        }
        for (int i = 0; i < magazine.length(); i++) {
            // 通过recode数据记录 magazine里各个字符出现次数
            record[magazine[i]-'a'] ++;
        }
        for (int j = 0; j < ransomNote.length(); j++) {
            // 遍历ransomNote,在record里对应的字符个数做--操作
            record[ransomNote[j]-'a']--;
            // 如果小于零说明ransomNote里出现的字符,magazine没有
            if(record[ransomNote[j]-'a'] < 0) {
                return false;
            }
        }
        return true;
    }
};

python

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:

        arr = [0] * 26

        for x in magazine:
            arr[ord(x) - ord('a')] += 1

        for x in ransomNote:
            if arr[ord(x) - ord('a')] == 0:
                return False
            else:
                arr[ord(x) - ord('a')] -= 1
        
        return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

joker-wt

我的心愿是——世界和平

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值