算法练习-赎金信(思路+流程图+代码)

难度参考

        难度:中等

        分类:哈希表

        难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。

题目

        给你两个字符串:ransomNote 和 magazine,判断ransomNote 能不能由magazine 里面的字符构成。如果可以,返回true;否则返回false

        示例1:

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

        示例2:

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

        额外提示:

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

        ransomNote和magazine由小写英文字母组成

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

思路

        为了确认能否从 magazine 字符串中得到 ransomNote 字符串所需的所有字符,我们必须比较这两个字符串中各字符的出现次数。这可以通过以下步骤实现:

  1. 统计 magazine 中字符的频率
    创建一个大小为 26 的数组或向量用以表示每个字母的计数器,因为假设字符串仅包含小写字母。遍历 magazine 并增加每个字符相对应的计数器。

  2. 检查 ransomNote 的字符
    遍历 ransomNote,对于每个字符,减少其在计数器数组中对应的值。如果在减少之前某个字符的计数器值已经是 0,说明 magazine 中没有足够的字符以形成 ransomNote

  3. 结果判断
    如果所有字符在减少计数器时都没有产生负值,即 magazine 含有足够的每个字符以构建 ransomNote,则返回 true。否则,如果任何字符的计数器值变为负,说明 magazine 中缺乏足够的该字符,无法构建 ransomNote,返回 false。

示例

        假设我们有以下两个字符串:

        ransomNote: “aab”
        magazine: “baa”

        我们想要检查是否可以从杂志字符串 “magazine” 中剪下字母构造出勒索信 “ransomNote”。我们的方法是按照字母计数来检查。以下是对应的步骤和发生的事情:

  1. 初始化字符计数:

    我们创建了一个大小为 26 的数组或向量 charCount 来记录每个字母的出现次数。因为我们只处理小写字母,所以我们不需要更大的大小。每个位置初始化为 0。

  2. 统计 magazine 中的字符:

    对于字符串 “baa”,我们执行以下操作:

    • ‘b’ -> charCount['b' - 'a'](即 charCount[1])将从 0 变成 1。
    • ‘a’ -> charCount['a' - 'a'](即 charCount[0])将从 0 变成 1。
    • 另一个 ‘a’ -> charCount[0] 将从 1 变成 2。

    charCount 向量现在包含:[2, 1, 0, 0, …, 0],因为 ‘a’ 出现了两次,‘b’ 出现了一次,其他字母出现了零次。

  3. 检查 ransomNote 中的字符:

    对于字符串 “aab”,我们执行以下操作:

    • ‘a’ -> charCount[0] 从 2 减到 1。
    • 另一个 ‘a’ -> charCount[0] 从 1 减到 0。
    • ‘b’ -> charCount[1] 从 1 减到 0。

    在这个过程中,charCount 向量的每个相关位置至少为 0,这意味着 magazine 中每个所需字符的数量都足够 ransomNote 使用。

  4. 返回结果:

    由于 charCount 中没有任何索引变为负数,我们可以得出结论,在 magazine 中总是有足够的每个字符来构建 ransomNote,因此函数返回 true。

这就是代码的基本工作原理。通过遍历 ‘magazine’ 增加计数,然后遍历 ‘ransomNote’ 减少计数,最后根据计数结果决定是否可以构建出 ‘ransomNote’。

梳理

        这种方法之所以能够实现,是因为我们在检查能否从 `magazine` 得到 `ransomNote` 所需的所有字符时,遵循了两个基本原则:

        1. 频率匹配原则:
   每个字符在 `ransomNote` 中出现的频率不能高于在 `magazine` 中出现的频率。如果 `ransomNote` 需要比 `magazine` 提供更多的某个字符,这显然是不可能的,因为你不能从 `magazine` 中得到比它本身更多的某个字符。

        2. 字符独立原则:
   字符的使用是独立的。即,一个 'a' 的出现与另一个 'a' 的出现无关,它们可以独立计算。这使得我们可以通过简单地计数每个字符来跟踪 `magazine` 中有多少个 'a',而不必关心它们在字符串中的位置或顺序。

        当我们使用一个大小为 26 的数组(针对 26 个小写字母)来统计 `magazine` 中各字母的出现次数时,我们就执行了一个由字符到频率的映射。由于 `ransomNote` 可能包含重复的字母,通过逐个检查并递减 `magazine` 中的相应字母计数,我们实际上是在确认是否对于 `ransomNote` 中的每个字符,`magazine` 都至少有相等数量的该字符。

        这个检查过程中,如果发现某个字符在 `magazine` 中的计数已经为零(即已经被 'ransomNote' 用尽),然后 `ransomNote` 还需要该字符,那么说明 `magazine` 不能满足 `ransomNote` 的需求。

        因为这种方法直接通过频率匹配来确定是否可行,所以它是高效且有效的。它不必关心两个字符串的任何其他复杂关系,如它们的子序列关系或排序。当我们完成了遍历整个 `ransomNote` 名称,并且没有发现任何计数不足以匹配需求的情况时,我们就可以确定 `magazine` 可以提供足够的字符来构建 `ransomNote`。

代码

#include <iostream> // 包含输入/输出流库
#include <vector>   // 包含 vector 容器库
#include <string>   // 包含 string 类库
using namespace std; // 使用 std 命名空间,避免 std:: 前缀// 函数 canConstruct 用于判断是否能够通过 magazine 的字母构造出 ransomNote
bool canConstruct(string ransomNote, string magazine) {vector<int> charCount(26, 0); // 创建一个大小为 26 的整数向量,用于计数每个字符的出现次数,初始化为 0for (char ch : magazine) { // 遍历 magazine 中的每个字符++charCount[ch - 'a']; // 增加 magazine 中当前字符的计数}for (char ch : ransomNote) { // 遍历 ransomNote 中的每个字符if (--charCount[ch - 'a'] < 0) { // 减少 ransomNote 中当前字符的计数,如果计数小于 0 则返回 falsereturn false;}}return true; // 如果 ransomNote 中的所有字符都能在 magazine 中找到,则返回 true
}int main() {string ransomNote1 = "a"; // 初始化测试用例 1 的 ransomNote  string magazine1 = "b";   // 初始化测试用例 1 的 magazine// 输出测试结果:使用可以构造的函数结果,并转换为 "true" 或 "false" 字符串cout << (canConstruct(ransomNote1, magazine1) ? "true" : "false") << endl;string ransomNote2 = "aa"; // 初始化测试用例 2 的 ransomNotestring magazine2 = "ab";   // 初始化测试用例 2 的 magazine// 输出测试结果:使用可以构造的函数结果,并转换为 "true" 或 "false" 字符串cout << (canConstruct(ransomNote2, magazine2) ? "true" : "false") << endl;return 0; // main 函数正常终止
}

        事实上还可以在开始前判断一下长度,长度不同直接否决,这边没写。

        时间复杂度:O(n)

        空间复杂度:O(1)

打卡

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/473505.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【mysql】数据约束

一、数据约束&#xff1a; 什么是约束&#xff1f; 为了确保表中的数据的完整性(准确性、正确性)&#xff0c;为表添加一些限制。是数据库中表设计的一个最基本规则。使用约束可以使数据更加准确&#xff0c;从而减少冗余数据&#xff08;脏数据&#xff09;。 数据库完整性约…

HarmonyOS—@State装饰器:组件内状态

State装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI会发生对应的渲染改变。 在状态变量相关装饰器中&#xff0c;State是最基础的&#xff0c;使变量拥有状态属性的装饰器&a…

CSS 不同颜色的小圆角方块组成的旋转加载动画

<template><!-- 创建一个装载自定义旋转加载动画的容器 --><view class="spinner"><!-- 定义外部包裹容器,用于实现整体旋转动画 --><view class="outer"><!-- 定义四个内部小方块以形成十字形结构 --><view clas…

如何让Obsidian实现电脑端和安卓端同步

Obsidian是一款知名的笔记软件&#xff0c;支持Markdown语法&#xff0c;它允许用户在多个设备之间同步文件。要在安卓设备上实现同步&#xff0c;可以使用remote save插件&#xff0c;以下是具体操作步骤&#xff1a; 首先是安装电脑端的obsidian&#xff0c;然后依次下载obs…

MOSFET栅极应用电路分析汇总(驱动、加速、保护、自举等等)

概述 MOSFET是一种常见的电压型控制器件&#xff0c;具有开关速度快、高频性能、输入阻抗高、噪声小、驱动功率小、动态范围大、安全工作区域(SOA)宽等一系列的优点&#xff0c;因此被广泛的应用于开关电源、电机控制、电动工具等各行各业。栅极做为MOSFET本身较薄弱的环节&am…

Python如何实现定时发送qq消息

因为生活中老是忘记各种事情&#xff0c;刚好又在学python&#xff0c;便突发奇想通过python实现提醒任务的功能&#xff08;尽管TIM有定时功能&#xff09;&#xff0c;也可定时给好友、群、讨论组发送qq消息。其工作流程是&#xff1a;访问数据库提取最近计划——>根据数据…

Java - SPI机制

本文参考&#xff1a;SPI机制 SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;可以用来启动框架扩展和替换组件&#xff0c;主要是被框架的开发人员使用&#xff0c;比如 java.sql.Driver接口&#xff0c;其他…

基于SSM的社区疫情防控管理系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的社区疫情防控管理系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

torch.utils.data

整体架构 平时使用 pytorch 加载数据时大概是这样的&#xff1a; import numpy as np from torch.utils.data import Dataset, DataLoaderclass ExampleDataset(Dataset):def __init__(self):self.data [1, 2, 3, 4, 5]def __getitem__(self, idx):return self.data[idx]def…

祝所有的CSDN社区成员们新年快乐

文章目录 尊敬的CSDN社区成员们&#xff0c; 在新年的钟声即将敲响之际&#xff0c;我携带着满心祝福与期许&#xff0c;以字为舟&#xff0c;穿越虚拟与现实的界限&#xff0c;来到您的身边&#xff0c;向每一位热爱编程、投身技术研究、在CSDN平台上挥洒智慧和汗水的朋友们&a…

Netty中的适配器、Handler共享和资源管理

ChannelHandler的适配器 有一些适配器类可以将编写自定义的ChannelHandler所需要的工作降到最低限度&#xff0c; 因为它们提供了定义在对应接口中的所有方法的默认实现。因为有时会忽略那些不感兴趣的 事件&#xff0c;所以Netty提供了抽象积累ChannelInboundHandlerAdapter(…

深夜突发! OpenAI震撼发布了SORA文生视频模型,对职场人的影响可能跟你想的不一样

深夜突发! OpenAI震撼发布了SORA文生视频模型&#xff0c;对职场人的影响可能跟你想的不一样。 马上就要节后返工了&#xff0c;顾问老师也早已回到了温暖的广州。与一位同城的学员相聚在老广州的一个茶楼中&#xff0c;喝起了下午茶。面对各式的广式茶点&#xff0c;在淡淡的茶…