题解 | #字符串构造判定#

字符串构造判定

https://www.nowcoder.com/practice/8d6a87b1e5314c0387dad5728dcc05be

题目链接

字符串构造判定

题目描述

给定两个仅由小写英文字母构成的字符串 ransomNotemagazine

请判断是否可以从 magazine 中选取若干字符(每个字符最多使用一次),拼接成与 ransomNote 完全相同的字符串。

这是一个 核心代码模式 (Core Code Mode) 的题目,你只需要实现 canConstruct 函数。

示例 1: 输入:

"wc", "nowcoder"

输出:

true

解题思路

这道题的本质是检查 "magazine 字符串中的字符数量,是否足够满足 ransomNote 字符串中每个字符的需求"。

我们可以使用 字符计数(哈希表) 的方法来高效解决。由于题目限定字符都是小写英文字母,我们可以用一个大小为 26 的数组来充当哈希表,这比通用的 HashMapunordered_map 效率更高。

算法步骤:

  1. 初步剪枝: 如果 ransomNote 的长度大于 magazine 的长度,那么 magazine 肯定无法凑出 ransomNote,可以直接返回 false。这是一个有效的优化。
  2. 建立字符库: 创建一个大小为 26 的整型数组 counts。遍历 magazine 字符串,统计其中每个字符出现的次数。例如,遇到字符 'a',就将 counts[0] 加一;遇到 'b',就将 counts[1] 加一,以此类推(counts[ch - 'a']++)。
  3. 消耗字符: 遍历 ransomNote 字符串。对于遇到的每一个字符 ch,我们从字符库中"取走"一个,即将 counts 数组中对应的计数减一(counts[ch - 'a']--)。
  4. 检查库存: 在每次消耗字符后,立刻检查该字符的库存是否足够。如果 counts 中对应的值变为负数,说明 magazine 中没有足够的该种字符来构造 ransomNote,应立即返回 false
  5. 成功构造: 如果整个 ransomNote 遍历完成,都没有出现库存不足的情况,说明 magazine 中的字符足够,可以成功构造。返回 true

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * @param ransomNote string字符串 
     * @param magazine string字符串 
     * @return bool布尔型
     */
    bool canConstruct(string ransomNote, string magazine) {
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        
        vector<int> counts(26, 0);
        for (char ch : magazine) {
            counts[ch - 'a']++;
        }
        
        for (char ch : ransomNote) {
            counts[ch - 'a']--;
            if (counts[ch - 'a'] < 0) {
                return false;
            }
        }
        
        return true;
    }
};
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * @param ransomNote string字符串 
     * @param magazine string字符串 
     * @return bool布尔型
     */
    public boolean canConstruct(String ransomNote, String magazine) {
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        
        int[] counts = new int[26];
        for (char ch : magazine.toCharArray()) {
            counts[ch - 'a']++;
        }
        
        for (char ch : ransomNote.toCharArray()) {
            counts[ch - 'a']--;
            if (counts[ch - 'a'] < 0) {
                return false;
            }
        }
        
        return true;
    }
}
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param ransomNote string字符串 
# @param magazine string字符串 
# @return bool布尔型
#
from collections import Counter
class Solution:
    def canConstruct(self , ransomNote: str, magazine: str) -> bool:
        # 如果赎金信更长,直接返回 False
        if len(ransomNote) > len(magazine):
            return False
        
        # 使用 Counter 进行字符计数,非常高效和 Pythonic
        # a - b 会得到一个计数器,其中包含 a 有但 b 没有或 b 不足的元素
        # 如果结果为空或者所有值的计数都小于等于0,则说明 b 足以构成 a
        return not (Counter(ransomNote) - Counter(magazine))

算法及复杂度

  • 算法: 字符计数 (Frequency Array / Hash Map)
  • 时间复杂度: ,其中 magazine 的长度,ransomNote 的长度。我们需要分别遍历两个字符串一次。
  • 空间复杂度: ,其中 是字符集的大小(本题中为26)。由于字符集大小是固定的,所以空间复杂度为常数。
全部评论

相关推荐

09-08 17:17
同济大学 Java
狗不理fe:里面的人劝一句,别来虾,我们部门24校招生淘汰率30%,还有一些人说有一年保护期,不可能!!!
我的秋招日记
点赞 评论 收藏
分享
夏日狂想曲:连体婴是这样的,不过国内还有上四休三的公司?
点赞 评论 收藏
分享
昨天 16:33
门头沟学院 Java
本人某中9本科,成绩中等,目前没科研没实习,目前后端学到了javaWeb,开始没定好方向,在学国外课程,走工程路线起步有点晚了,到这个时间点了还在学JavaWeb,顿感迷茫,不知道是坚持走下去还是寒假去准备考研。考研这个路弄得我还是心痒痒的,因为从众考研的人也不在少数,所以会有这方面的心理安慰吧,就是“不行我可以去考研啊”,而且意味着三年的缓冲,为了复试还有积攒经验美化简历,其实现在也可以去申入实验室打杂;就业可能意味着多些工作经验,工程岗应该到后面还是经验大于学历?还是有点迷茫了,求助好心人有无路线启发
千千倩倩:同27给点建议,现在这个时间点可以快速看完外卖和点评,不用跟着敲,但一定要在看的时候总结每个部分的整个业务流程,对其中的实现有一个大概的印象。然后直接开始看八股,刷算法。八股和算法最好还是在项目学习中穿插着看。如果计算机基础,算法这些基础好,加上每天刻苦学习,两周可以达到勉强能面试的水平,到时候就直接海投中小厂,在约面和面试的过程中不断巩固知识。没找到实习也没关系,就当积累经验。再沉淀一波直接明年三月开始投暑期,毕竟是9本,总是有面试机会的,只要你这三个月不懈怠,面试发挥得一定不错,只要拿到一个中,大厂暑期实习,秋招就有竞争力了。总得而言,现在还有机会,但是时间非常紧张,需要你结合自己情况考虑,共勉
你会选择考研还是直接就业
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务