C++前缀和算法:统计美丽子字符串

题目

给你一个字符串 s 和一个正整数 k 。
用 vowels 和 consonants 分别表示字符串中元音字母和辅音字母的数量。
如果某个字符串满足以下条件,则称其为 美丽字符串 :
vowels == consonants,即元音字母和辅音字母的数量相等。
(vowels * consonants) % k == 0,即元音字母和辅音字母的数量的乘积能被 k 整除。
返回字符串 s 中 非空美丽子字符串 的数量。
子字符串是字符串中的一个连续字符序列。
英语中的 元音字母 为 ‘a’、‘e’、‘i’、‘o’ 和 ‘u’ 。
英语中的 辅音字母 为除了元音字母之外的所有字母。
示例 1:
输入:s = “baeyh”, k = 2
输出:2
解释:字符串 s 中有 2 个美丽子字符串。

  • 子字符串 “baeyh”,vowels = 2([“a”,“e”]),consonants = 2([“y”,“h”])。
    可以看出字符串 “aeyh” 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
  • 子字符串 “baeyh”,vowels = 2([“a”,“e”]),consonants = 2([“b”,“y”])。
    可以看出字符串 “baey” 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
    可以证明字符串 s 中只有 2 个美丽子字符串。
    示例 2:
    输入:s = “abba”, k = 1
    输出:3
    解释:字符串 s 中有 3 个美丽子字符串。
  • 子字符串 “abba”,vowels = 1([“a”]),consonants = 1([“b”])。
  • 子字符串 “abba”,vowels = 1([“a”]),consonants = 1([“b”])。
  • 子字符串 “abba”,vowels = 2([“a”,“a”]),consonants = 2([“b”,“b”])。
    可以证明字符串 s 中只有 3 个美丽子字符串。
    示例 3:
    输入:s = “bcdf”, k = 1
    输出:0
    解释:字符串 s 中没有美丽子字符串。
    参数范围
    1 <= s.length <= 5 * 104
    1 <= k <= 1000
    s 仅由小写英文字母组成。

方法一

分析

时间复杂度

O(n)

大致步骤

记录前缀和后,枚举左右端点。

setVowel所有元音字符
vPre1[i]前i个字符中元音的数量
vPre2[i]前i个字符中辅音的数量

代码

核心代码

class Solution {
public:
int beautifulSubstrings(string s, int k) {
m_c = s.length();
std::unordered_set setVowel = { ‘a’,‘e’,‘i’,‘o’ , ‘u’ };
vector vPre1 = { 0 }, vPre2 = { 0 };
for (const char& ch : s)
{
if (setVowel.count(ch))
{
vPre1.emplace_back(vPre1.back() + 1);
vPre2.emplace_back(vPre2.back() );
}
else
{
vPre1.emplace_back(vPre1.back() );
vPre2.emplace_back(vPre2.back() + 1);
}
}
int iRet = 0;
for(int i = 0 ; i < m_c ; i++ )
for (int j = i; j < m_c; j++)
{
const int iNum1 = vPre1[j + 1] - vPre1[i];
const int iNum2 = vPre2[j + 1] - vPre2[i];
if (iNum1 != iNum2)
{
continue;
}
if (0 != iNum1 * iNum2% k )
{
continue;
}
iRet++;
}
return iRet;
}
int m_c;
};

测试用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}
int main()
{
string s;
int k,res;
{
Solution slu;
s = “baeyh”;
k = 2;
res = slu.beautifulSubstrings(s, k);
Assert(res, 2);
}
{
Solution slu;
s = “abba”;
k = 1;
res = slu.beautifulSubstrings(s, k);
Assert(res, 3);
}
{
Solution slu;
s = “bcdf”;
k = 1;
res = slu.beautifulSubstrings(s, k);
Assert(res, 0);
}
{
Solution slu;
s = “ihroyeeb”;
k = 5;
res = slu.beautifulSubstrings(s, k);
Assert(res, 0);
}
}

方案二

s[left,right]是美丽字符的条件。
一,元音辅音相等。我们记录所有sub[left] = vPre1[left]-vPre2[left],即元音辅音之差。如果sub[left]等于sub[right],则元音辅音相等。
二,数量的平方是k的倍数。我可以转成等效问题:数量必须是m的倍数。如:k=4,则m=2。k=3,则m=3。k=12,m=6。显然:m小于等于k,且m不会为0。对于每个left,我们无需记录它的元音数量,只需要记录它的元音数量%m。

时间复杂度

如果用有序映射记录状态的数量,则时间复杂度为:O(nlognm)。
枚举每个每个美丽字符串的右端点时间复杂度O(n),查询合法的对应left数量O(lognm)。如果用哈希映射记录状态和数量,总时间复杂度降到O(n)。

代码

class Solution {
public:int beautifulSubstrings(string s, int k) {m_c = s.length();std::unordered_set<char> setVowel = { 'a','e','i','o' , 'u' };vector<int> vPre1 = { 0 }, vPre2 = { 0 };for (const char& ch : s){if (setVowel.count(ch)){vPre1.emplace_back(vPre1.back() + 1);vPre2.emplace_back(vPre2.back());}else{vPre1.emplace_back(vPre1.back());vPre2.emplace_back(vPre2.back() + 1);}}int m = 0;for (m = 1; 0 != m * m % k; m++);int iRet = 0;std::unordered_map<int, std::unordered_map<int,int>> mSub;for (int i = 0; i < m_c; i++){const int iSub = vPre1[i+1] - vPre2[i+1];const int iNeed = vPre1[i + 1] % m;if (mSub.count(iSub)){if(mSub[iSub].count(iNeed)){iRet += mSub[iSub][iNeed];}}{const int iSub = vPre1[i] - vPre2[i];mSub[iSub][vPre1[i]%m]++;}}return iRet;}int m_c;
};

优化代码

分析

优化点:
一,无需前缀和,记录当前元音数量就可以了。当前辅音数量=当前字符总数量-当前元音数量。
二,用std::pair<int,int> 做key。

代码

class Solution {
public:int beautifulSubstrings(string s, int k) {m_c = s.length();std::unordered_set<char> setVowel = { 'a','e','i','o' , 'u' };int m = 0;for (m = 1; 0 != m * m % k; m++);int iRet = 0;int iVowelNum = 0;std::map<std::pair<int, int>, int> mSubVowelToNum;for (int i = 0; i < m_c; i++){const int preVowel = iVowelNum;if (setVowel.count(s[i])){iVowelNum++;}const int iSub = iVowelNum - (i+1- iVowelNum);//当前元音数量减辅音数量auto pr = std::make_pair(iSub, iVowelNum%m);if (mSubVowelToNum.count(pr)){iRet += mSubVowelToNum[pr];}{const int iSub = preVowel - (i  - preVowel);auto pr = std::make_pair(iSub, preVowel%m);mSubVowelToNum[pr]++;}}return iRet;}int m_c;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境:

VS2022 C++17

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

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

相关文章

Jenkins与Docker的自动化CI/CD流水线实践

Pipeline 有诸多优点&#xff0c;例如&#xff1a; 项目发布可视化&#xff0c;明确阶段&#xff0c;方便处理问题 一个Jenkins File文件管理整个项目生命周期 Jenkins File可以放到项目代码中版本管理 Jenkins管理界面 操作实例&#xff1a;Pipeline的简单使用 这里是比较…

elastic -job和springboot集成实现分布式调度5

一 案例介绍说明 1.1 案例介绍 基于 Spring boot 集成方式的而产出的工程代码&#xff0c;完成对作业分片的实现&#xff0c;文件数据备份采取更接近真实项目的数 据库存取方式。 1.分片设置 2.每个线程获取给自的类型 1.2 作业配置 zk的配置 二 操作说明 2.1 数据表的初始…

深入理解计算机中的程序

目录 程序的存储 程序的编译过程 各位宝宝好&#xff0c;我们这次从计算机底层来讲一下程序是如何存储&#xff0c;编译的 程序的存储 我们拿一个最简单的程序来举个例子&#xff1a; #include<stdio.h> int main() {printf("hello world");return 0; } …

类与对象(下)

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX&#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&a…

设计模式精讲:掌握单例模式的实现与优化

掌握单例模式的实现与优化 一、引言&#xff1a;如何学习设计模式&#xff1f;二、前置知识&#xff1a;对象的创建的销毁2.1、拷贝构造2.2、拷贝赋值构造2.3、移动构造2.4、移动赋值构造 三、单例模式的定义四、单例模式的实现与优化4.1、版本一4.2、版本二4.3、版本三4.4、版…

ros2智能小车中STM32地盘需要用到PWM的模块

我做的地盘比较简单&#xff0c;使用了一下模块&#xff1a; 4个直流减速电机&#xff0c;&#xff08;每个模块用到了一个PWM&#xff09;---这会通过L298N的ENA,ENB来实现控制 光电对射测速模块&#xff08;不用PWM) 超声波测距模块&#xff08;不用PWM&#xff0c;只需要…

靡靡之音 天籁之声 ——Adobe Audition

上一期讲到了和Pr配合使用的字幕插件Arctime Pro的相关介绍。相信还记得的小伙伴应该记得我还提到过一个软件叫做Au。 当人们对字幕需求的逐渐满足&#xff0c;我们便开始追求更高层次的享受&#xff0c;当视觉享受在进步&#xff0c;听觉享受想必也不能被落下&#xff01; Au即…

NX二次开发UF_CURVE_ask_offset_parms 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_offset_parms Defined in: uf_curve.h int UF_CURVE_ask_offset_parms(tag_t offset_curve_object, UF_CURVE_offset_data_p_t offset_data_pointer ) overview 概述 …

什么是好的FPGA编码风格?(3)--尽量不要使用锁存器Latch

前言 在FPGA设计中&#xff0c;几乎没人会主动使用锁存器Latch&#xff0c;但有时候不知不觉中你的设计莫名其妙地就生成了一堆Latch&#xff0c;而这些Latch可能会给你带来巨大的麻烦。 什么是锁存器Latch&#xff1f; Latch&#xff0c;锁存器&#xff0c;一种可以存储电路…

Spring Boot 项目配置文件出现乱码的解决方法

如下图&#xff0c;我们 Spring Boot 项目的配置文件 application.properties 可能会出现如下的乱码问题&#xff1a; 我们写注解的时候是正常的&#xff0c;但是下次启动项目就出现了乱码&#xff0c;这个是字符集设置的问题 解决方法 1.点击 File 选择 Settings 2.搜索 enco…

Grabcut算法在图片分割中的应用

GrabCut算法原理 Grabcut是基于图割(graph cut)实现的图像分割算法&#xff0c;它需要用户输入一个bounding box作为分割目标位置&#xff0c;实现对目标与背景的分离/分割&#xff0c;与KMeans与MeanShift等图像分割方法不同。 Grabcut分割速度快&#xff0c;效果好&#xff0…

stm32 42步进电机 上位机示例

脉冲到底是个啥东西&#xff1f;步进电机一直说发脉冲 步进电机通过接收脉冲信号来实现精确的位置控制。脉冲是一种短暂的电信号&#xff0c;它的变化可以触发步进电机转动一定的角度或步进。步进电机控制系统会根据输入的脉冲信号来精确定位和控制步进电机的转动&#xff0c;每…

YOLOv8 训练自己的分割数据集

之前写过一篇 使用YOLOv8训练自己的【目标检测】数据集-【收集数据集】-【标注数据集】-【划分数据集】-【配置训练环境】-【训练模型】-【评估模型】-【导出模型】&#xff0c;里面带大家整个流程走过一遍了&#xff0c; 这篇文章我们来介绍如何使用 YOLOv8 训练分割数据集&a…

Linux篇:文件系统

一、共识原理&#xff1a; 文件文件内容文件属性 磁盘上存储文件存文件的内容&#xff08;数据块&#xff09;存文件的属性&#xff08;inode&#xff09; Linux的文件在磁盘中存储是将属性和内容分开存储的。 二、硬件简述&#xff1a; 1. 认识硬件 磁盘&#xff1a;唯一的一…

LabVIEW绘制带有多个不同标尺的波形图

LabVIEW绘制带有多个不同标尺的波形图 通过在同一波形图上使用多个轴&#xff0c;可以使用不同的标尺绘制数据。请按照以下步骤操作。 将波形图或图表控件放在前面板上。 1. 右键点击您要创建多个标尺的轴&#xff0c;然后选择复制标尺。例如&#xff0c;如果要为一个…

文件搜索工具HoudahSpot mac中文版特点

HoudahSpot mac是一款文件搜索工具&#xff0c;它可以帮助用户快速准确地找到文件和文件夹&#xff0c;支持高级搜索和过滤&#xff0c;同时提供了多种视图和操作选项&#xff0c;方便用户进行文件管理和整理。 HoudahSpot mac软件特点 高级搜索和过滤功能&#xff1a;软件支持…

手把手教会你--github的学习--持续更新

有什么问题&#xff0c;请尽情问博主&#xff0c;QQ群796141573 前言1.1 使用过程(1) 进入某个项目(2) 点击某个文件(3) 在源码区域下面(4) 源码区的头顶上 1.2 作者的其他项目1.3 搜索1.4 复制别人的代码(即项目)到自己的空间内1.5 上传自己的Bugs(bushi1.6 在线修改文件1.7 评…

【非监督学习 | 聚类】聚类算法类别大全 距离度量单位大全

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

JPA 自关联 设置单向多对一

Spring boot 3 JPA中&#xff0c;遇到一个需求&#xff0c;建一个数据字典表&#xff1a; Dictionary&#xff0c;存放两级数据&#xff0c;第一级为字典项目&#xff0c;第二级为项目内容&#xff0c;查询时要把parent_id对应父项的名称也一起查出来&#xff0c;返回前端。 …

Project DESFT 白皮书中文版——应用于普惠金融的可信数字凭证解决方案

1. 概述 Project DESFT 是由 Solv 基金会与 zCloak Network 联合设计孵化&#xff0c;以跨境贸易和金融服务为场景的分布式可信数字凭证解决方案&#xff08;Distributed Trusted Digital Credential Solution&#xff09;&#xff0c;项目获得新加坡金管局&#xff08;Monetar…