LeetCode 383 赎金信

1. 题目

383. 赎金信

题目描述

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

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

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

示例

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

输出:false

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

输出:false

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

输出:true

约束

  • (1 <= ransomNote.length, magazine.length <= 10^5)

  • 两个字符串均由小写英文字母组成

2. 最佳解题思路描述(字母计数数组,最优)

  1. 只有 26 个小写字母,开辟长度 26 的数组统计字符出现次数;

  2. 先遍历 magazine,对应字母位置计数 + 1;

  3. 再遍历 ransomNote,对应字母位置计数 - 1;

  4. 最后遍历计数数组,若存在任意位置数值小于 0,说明赎金信需要的字符数量多于杂志拥有,返回 false;全部≥0 则返回 true。

优势

  • 时间复杂度 (O(m+n)),m、n 为两个字符串长度,仅两次遍历;

  • 空间复杂度 (O(1)),固定长度 26 数组,常数空间;

  • 相比哈希表 unordered_map,数组寻址更快、无哈希冲突开销,本题首选。

3. 可优化代码(逻辑完全标准最优,仅微小格式优化)

复制代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int Arr[26] = {0};
        for(char c : magazine){
            Arr[c-'a']++;
        }
        for(char c : ransomNote){
            Arr[c-'a']--;
        }
        for(int i : Arr){
            if(i<0){
                return false;
            }
        }
        return true;
    }
};

代码说明

  1. 正确性:无任何逻辑 bug,能通过全部测试用例,是本题标准最优解法;

  2. 细微优化点(不影响 AC,仅提升规范度):

    • 数组名 Arr 语义模糊,改为 cnt / count 更易懂;

    • 可在遍历赎金信时提前判断,计数减为 0 直接返回 false,省去最后一轮完整遍历;

    • 变量、循环增加空格,代码可读性更好。

4. 规范优化版(提前终止,减少一轮遍历)

复制代码
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int cnt[26] = {0};
        // 统计杂志字符
        for (char c : magazine) {
            cnt[c - 'a']++;
        }
        // 匹配赎金信,中途不足直接返回false
        for (char c : ransomNote) {
            int idx = c - 'a';
            cnt[idx]--;
            if (cnt[idx] < 0) {
                return false;
            }
        }
        return true;
    }
};

5. 总结

  1. 数组计数思路完全正确、性能最优;

  2. 核心逻辑:杂志字符做加法,赎金信字符做减法,负数代表字符不够;

  3. 26 个小写字母固定场景,优先用数组而非哈希表;

  4. 优化小技巧:遍历赎金信时实时判断,提前 return,不用完整遍历 26 个数字。

6. 相关知识拓展

拓展 1:哈希表写法(不推荐,开销更大)

字符种类少时数组完胜哈希,仅字符范围大时选用:

复制代码
#include <unordered_map>
bool canConstruct(string ransomNote, string magazine) {
    unordered_map<char, int> mp;
    for (char c : magazine) mp[c]++;
    for (char c : ransomNote) {
        mp[c]--;
        if (mp[c] < 0) return false;
    }
    return true;
}

拓展 2:同类字符计数模板题

  • LC242 有效的字母异位词(同样 26 数组统计,最终全部为 0)

  • LC438 找到字符串中所有字母异位词(滑动窗口 + 26 计数数组)

  • LC125 验证回文串(字符筛选 + 计数)

拓展 3:复杂度对比

  1. 26 计数数组(优化后):(O(m+n)) 时间,(O(1)) 空间(最优);

  2. unordered_map 哈希表:(O(m+n)) 时间,(O(1)) 理论空间,但常数开销更大;

拓展 4:易错点复盘

  1. 颠倒遍历顺序:先遍历 ransomNote 再加 magazine,逻辑完全颠倒;

  2. 忘记判断 <0,只判断等于 0,无法识别字符数量不足;

  3. 使用大写 / 混合字符时未做范围判断(本题限定全小写无需处理)。

相关推荐
飘尘11 小时前
从"算子"到"AI Infra":大模型背后看不见的那群人在忙什么
人工智能·算法·面试
夏幻灵12 小时前
每日一题:LeetCode 3:无重复字符的最长子串——滑动窗口思路详解
算法·leetcode·职场和发展
CarIise12 小时前
Java实训阶段查漏补缺复习笔记2
java·linux·算法
无忧.芙桃12 小时前
C++ 并查集详解:原理、实现与应用
c语言·c++·算法·leetcode
蛋蛋的就会顺顺的12 小时前
hot100——二叉树
java·数据结构·算法·leetcode·力扣
Code_Solitude13 小时前
c语言:二分法的完整补充
c语言·开发语言·算法
一切皆是因缘际会13 小时前
掌控信息论:同源星际通信基础理论
人工智能·算法·ai
动词ing15 小时前
【C语言题目练习】算法 整数反转
c语言·开发语言·算法
Nil20815 小时前
leetcode 55跳跃游戏
算法·leetcode·游戏
longlongzihan15 小时前
LeetCode 128. 最长连续序列 —— 从排序到哈希集合
数据结构·c++·算法·leetcode·排序算法·哈希表