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

难度参考

        难度:中等

        分类:哈希表

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

题目

        给你两个字符串: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`。

        这类问题被称作"哈希表"问题,是因为它涉及到对数据的快速查找和访问,哈希表是实现这种操作的理想数据结构。在你给出的 C++ 代码示例中,charCount 数组充当了一个简化的哈希表的角色,用于快速统计和检索字母的出现次数。

        哈希表(Hash Table)这一数据结构。哈希表是一种根据键(Key)直接访问在内存存储位置的数据结构。它使用一个哈希函数来计算一个值(键的哈希值),然后这个值决定了键在表中的位置。

        详细来说,charCount 通过将字符 ‘a’ 到 ‘z’ 映射到数组的索引 0 到 25 来简化哈希函数。在这种情况下,索引表示字母的哈希值,而数组的值表示特定字母在杂志字符串 magazine 中出现的次数。这是由以下代码段实现的:

for (char ch : magazine) {++charCount[ch - 'a']; // 对于每个字母,计数器位置是 ch - 'a'
}

        在上述代码段中,字符 ‘a’ 减去它自身 (‘a’ - ‘a’) 给出哈希值 0,字符 ‘b’ 减去 ‘a’ (‘b’ - ‘a’) 给出哈希值 1,依此类推,字符 ‘z’ 减去 ‘a’ (‘z’ - ‘a’) 给出哈希值 25。

        这样,我们就创建了一个特定于问题的、基于字符的哈希表,不需要使用复杂的哈希函数或处理哈希冲突,因为英文字母的数量是限定的(26个字母),所以我们可以保证每个字母都有一个唯一的哈希值,并且可以直接映射到数组的索引。

        之后在检查 ransomNote 字符串时,也使用到了这个哈希表来确认杂志字符串中是否包含足够数量的每个字母以构建 ransomNote

        这种对数据的快速访问和管理能力是哈希表的关键特点,也就是为什么这种类型的问题可以被归类为哈希表问题。在实际的应用中,哈希表通常是通过如 std::unordered_map 或 std::map 实现的,但基本概念与我们的简化模型相同。

代码

#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.mzph.cn/news/688398.shtml

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

相关文章

数智化转型|两大电网、五大发电2024年重点工作路线图!

2024年1月&#xff0c;两大电网、五大发电集团陆续召开2024年工作会议&#xff0c;明确了2024年工作目标及重点路线图。从工作会议内容来看&#xff0c;不难发现&#xff0c;加快推动数智化转型&#xff0c;建设新型电力系统成为几大集团未来共同发展目标。会议内容如下&#x…

大数据,对于生活的改变

谷歌通过对于疾病的查询量可以预测一个个h1n1病毒的大爆发&#xff0c; 大数据时代对于人的考验 用户的搜索记录就是一种信息&#xff0c;这种信息会满足其基础相关的词条与其有关的词条&#xff08;最为原始的搜索机制&#xff0c;国内的搜索引擎都是采用这种基础原理。&…

从源代码安装 rocSOLVER 并 调试 rocSOLVER 在 Ubuntu 22.04 平台

0, 下载并编译 rocBLAS 的调试版本 sudo apt install python3.10-venv sudo apt install libmsgpack-dev sudo pip install joblibgit clone --recursive https://github.com/ROCm/rocBLAS.git $ cd rocBLAS/ $ ./install.sh -i -g构建时间也不短 1&#xff0c;下载并编译 roc…

【数据结构与算法】手搓JDK底层ArrayList底层 - 动态数组

数组 在介绍数组之前&#xff0c;我们先来看一段chatGPT给出的对于数组描述&#xff1a; 数组&#xff08;Array&#xff09;是一种线性数据结构&#xff0c;它由一组连续的内存空间组成&#xff0c;用来存储相同类型的数据元素。数组具有固定的大小&#xff0c;一旦创建后&a…

分享几个丝滑oled代码

最近一段业余时间在捣鼓esp32&#xff0c;发现对于一个搞diy的来说&#xff0c;它的生态&#xff0c;不管是开发环境、氛围还是可玩度都是独一挡的&#xff0c;国内外基于此的扩展真是太多了&#xff0c;找了几个通过按键/旋钮进行0.96寸OLED控制的案例&#xff0c;超级丝滑&am…

SQL中的各种连接的区别总结

前言 今天主要的内容是要讲解SQL中关于Join、Inner Join、Left Join、Right Join、Full Join、On、 Where区别和用法&#xff0c;不用我说其实前面的这些基本SQL语法各位攻城狮基本上都用过。但是往往我们可能用的比较多的也就是左右连接和内连接了&#xff0c;而且对于许多初学…

JavaSE-02笔记【封装~this和static】

文章目录 1.封装&#xff08;掌握&#xff09;1.1 封装的理解1.2 不封装存在的问题1.3 怎么封装1.4 难点解惑1.5 练习 2. this 和 static2.1 this&#xff08;掌握&#xff09;2.1.1 this是什么2.1.2 this 在实例方法中使用2.1.3 this访问实例变量2.1.4 this扩展①2.1.5 this扩…

量子算法入门——3.狄拉克符号与量子态(2)

2. 光的极化和S-G实验 光的极化&#xff1a;表达出一方向电场的振动方式 S-G实验 银原子内部介绍 S-G实验过程 在炉子中将银原子高温灼烧&#xff0c;高温使得银原子具有极大的动能&#xff0c;从炉口向四周发射出来&#xff0c;炉口前设置两个小门构成两点一线&#xff…

Centos7挂载磁盘

1 查看未挂载的磁盘 命令&#xff1a; fdisk -l红框圈中的即是本次要挂载的磁盘&#xff0c;/dev/vdb 与 /dev/vda 相比&#xff0c;其没有下方的 /dev/vda1 等信息&#xff0c;代表 /dev/vdb 磁盘并没有进行过分区操作&#xff0c;是一个新加的硬盘。 2 对新建的磁盘进行分…

基于SSM的宁夏旅游网站平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的宁夏旅游网站平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring …

K8S之运用污点、容忍度设置Pod的调度约束

污点、容忍度 污点容忍度 taints 是键值数据&#xff0c;用在节点上&#xff0c;定义污点&#xff1b; tolerations 是键值数据&#xff0c;用在pod上&#xff0c;定义容忍度&#xff0c;能容忍哪些污点。 污点 污点是定义在k8s集群的节点上的键值属性数据&#xff0c;可以决…

Open CASCADE学习|管道建模

​这是用Open CASCADE Technology (OCCT)库来创建一个管道模型的示例。OCCT是一个开源的几何建模库&#xff0c;广泛应用于CAD/CAM/CAE和其他几何建模应用中。 在下面的代码中&#xff0c;首先创建了一些点&#xff0c;并用这些点来构建B样条曲线&#xff0c;进而创建边(Edges…

Java+Vue+MySQL,国产动漫网站全栈升级

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

软件测试经典面试题:如何进行支付功能的测试?

非现金支付时代&#xff0c;非现金支付已经成为了生活不可或缺的一部分&#xff0c;我们只需要一台手机便可走遍全国各地&#xff08;前提是支付宝&#xff0c;微信有钱<00>&#xff09;,那么作为测试人员&#xff0c;支付测试也是非常重要的一环&#xff0c;那么下面我就…

【漏洞复现-通达OA】通达OA swfupload_new存在前台SQL注入漏洞

一、漏洞简介 通达OA(Office Anywhere网络智能办公系统)是由北京通达信科科技有限公司自主研发的协同办公自动化软件,是与中国企业管理实践相结合形成的综合管理办公平台。通达OA为各行业不同规模的众多用户提供信息化管理能力,包括流程审批、行政办公、日常事务、数据统计…

作业2024/2/18

1.思维导图 2.定义一个基类Animal&#xff0c;其中有一个虚函数perform ()&#xff0c;用于在子类中实现不同的表演行为。 #include <iostream>using namespace std; class Animal { private:public:void virtual perform() 0;}; class Tiger:public Animal { private:…

树莓派驱动从认识框架到写驱动

​​​​​​参考文章&#xff1a;详细到吐血 —— 树莓派驱动开发入门&#xff1a;从读懂框架到自己写驱动_树莓派 编译驱动-CSDN博客 目录 一、对驱动的认识 为什么要学习驱动&#xff1f; 设备号的作用 二、基于内核驱动框架编写驱动代码流程 1、根据上层需求&…

ClickHouse从入门到精通(高级)

第1章 Explain查看执行计划 第2章 建表优化 第3章 ClickHouse语法优化规则 第4章 查询优化 第5章 数据一致性(重点) 第6章 物化视图 第7章 MaterializeMySQL引擎 第8章 常见问题排查

Python Selenium实现自动化测试及Chrome驱动使用!

本文将介绍如何使用Python Selenium库实现自动化测试&#xff0c;并详细记录了Chrome驱动的使用方法。 通过本文的指导&#xff0c;读者将能够快速上手使用Python Selenium进行自动化测试。 并了解如何配置和使用Chrome驱动来实现更高效的自动化测试。 一、Python Selenium简…

Java_方法(重载方法签名等详解)

在之前我们学习C语言时&#xff0c;当我们想要重复使用某段代码的功能时&#xff0c;我们会将这段代码定义为一个函数&#xff0c;而在java中我们把这段重复使用的代码叫做方法。 方法的定义 类体的内容分为变量的声明和方法的定义&#xff0c;方法的定义包括两部分&#xff1…