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

news2024/11/28 0:39:07

题目

给你一个字符串 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.coloradmin.cn/o/1257017.html

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

相关文章

光线追踪-Peter Shirley的RayTracingInOneWeekend系列教程(book1-book3)代码分章节整理

自己码完了一遍了&#xff0c;把代码分章节整理了一下&#xff0c;可以按章节独立编译&#xff0c;运行, 也可以直接下载编译好的release版本直接运行。 项目地址&#xff1a; Github: https://github.com/disini/RayTracingInOneWeekendChaptByChapt ​ ​ ​ ​

Rust语言入门教程(八) - 引用与借用

上一章的内容中我们讨论了Rust的所有权系统&#xff0c;当我们不想移动值的所有权时&#xff0c;我们可以使用引用和借用&#xff0c;而这正是本章想要讨论的问题。 引用&#xff08;References&#xff09; 引用允许你访问或修改数据而无需获取数据的所有权。在 Rust 中&…

Camtasia Studio2024专业的屏幕录制和视频剪辑软件

Camtasia2024专业的屏幕录制和视频剪辑软件3000多万专业人士在全球范围内使用Camtasia展示产品&#xff0c;教授课程&#xff0c;培训他人&#xff0c;以更快的速度和更吸引人的方式进行沟通和屏幕分享。使您在Windows和Mac上进行录屏和剪辑创作专业外观的视频变得更为简单。 …

【刷题笔记】加油站||符合思维方式

加油站 文章目录 加油站1 题目描述2 思路3 解题方法 1 题目描述 https://leetcode.cn/problems/gas-station/ 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消…

Blender 连续 5 天遭受大规模 DDoS 攻击

Blender 发布公告指出&#xff0c;在2023年11月18日至23日期间&#xff0c;blender.org 网站遭受了持续的分布式拒绝服务&#xff08;DDoS&#xff09;攻击&#xff0c;攻击者通过不断发送请求导致服务器超载&#xff0c;使网站运营严重中断。此次攻击涉及数百个 IP 地址的僵尸…

高并发系统:它的通用设计方法是什么?

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 我们知道&#xff0c;高并发代表着大流量&#xff0c;高并发系统设计的魅力就在于我们能够凭借自己的聪明才智设计巧妙的方案&#xff0c;从而抵抗巨大流量的冲击&#xff0c;带给用户更好的使用体验。这些方案好似能…

电子学会C/C++编程等级考试2021年09月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:余数相同问题 已知三个正整数 a,b,c。 现有一个大于1的整数x,将其作为除数分别除a,b,c,得到的余数相同。 请问满足上述条件的x的最小值是多少? 数据保证x有解。输入: 一行,三个不大于1000000的正整数a,b,c,两个整数…

ChatGPT初体验:注册、API Key获取与ChatAPI调用详解

自从2022年10月&#xff0c;ChatGPT诞生以后&#xff0c;实际上已经改变了很多&#xff01;其火爆程度简直超乎想象&#xff0c;一周的时间用户过百万&#xff0c;两个月的时间用户过亿。 目前ChatGPT4已经把2023年4月以前的人类的知识都学习到了&#xff0c;在软件工程里面&am…

因子分析例题(多元统计分析期末复习)

例一 设某客观现象可用 X {X} X( X 1 {X_1} X1​&#xff0c; X 2 {X_2} X2​&#xff0c; X 3 {X_3} X3​)’ 来描述&#xff0c;在因子分析时&#xff0c;从约相关阵出发计算特征值为 λ 1 {λ_1} λ1​1.754&#xff0c; λ 2 {λ_2} λ2​1&#xff0c; λ 3 {λ_3} λ3​…

3.数据结构

3.1 数据结构分类 常见的数据结构包括数组、链表、栈、队列、哈希表、树、堆、图&#xff0c;它们可以从“逻辑结构”和“物理结构”两个维度进行分类。 3.1.1逻辑结构&#xff1a;线性与非线性 逻辑结构揭示了数据元素之间的逻辑关系。在数组和链表中&#xff0c;数据按照…

【docker系列】docker命令篇

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C语言:有一篇文章,共三行文字,每行有80个字符。要求分别统计出单词个数、空格数。

分析&#xff1a; #include<stdio.h>&#xff1a;这是一个预处理指令&#xff0c;将stdio.h头文件包含到程序中&#xff0c;以便使用输入输出函数。 int main()&#xff1a;这是程序的主函数&#xff0c;是程序执行的入口点。 char a[3][80];&#xff1a;定义了一个二维…

springBoot的实现原理;SpringBoot是什么;使用SpringBoot的核心功能;springBoot核心注解以及核心配置文件

文章目录 springBootspringBoot的实现原理什么是 Spring Boot&#xff1f;SpringBoot是什么为什么要使用springBootSpring Boot的核心功能Spring Boot 主要有如下优点&#xff1a; SpringBoot启动过程-流程Spring Boot 的核心注解是哪个&#xff1f;什么是 JavaConfig&#xff…

7 通用数字量输入输出GPIO

文章目录 7.0 GPIO概念7.1 GPIO工作原理7.2 GPIO寄存器以及编程7.2.5 GPIO寄存器编程设置与应用 7.3 GPIO跑马灯7.3.1 LED 输出初始化7.3.2 跑马灯输出实验7.3.3 按键输入实验 7.0 GPIO概念 GPIO&#xff08;general purpose intput output&#xff09;是通用输入输出端口的简…

Elasticsearch:LangChain 是什么?

当你将应用程序称为 “AI&#xff08;人工智能&#xff09;” 时&#xff0c;这通常意味着它包含与学习模型&#xff08;例如大型语言模型&#xff0c;或 LLM&#xff09;的交互。 [不那么]有趣的事实是&#xff0c;LLM 的使用实际上并不是使应用程序变得智能的原因。 它的特殊…

vue项目npm install报错Failed at the fibersa4.0.3 install script

报错如下 解决&#xff1a;降低node版本 降到12.16.0 参考链接

基于51单片机的全自动洗衣机proteus仿真设计

标题目录 &#x1f4ab;51单片机全自动洗衣机proteus仿真设计&#x1f4ab;设计介绍&#x1f4ab;仿真图电动机驱动模块电路设计电源模块电路设计控制按键进水阀和排水阀控制继电器 &#x1f4ab;程序设计main函数 &#x1f4ab;设计报告&#x1f4ab;资料清单&&下载链…

【古诗生成AI实战】之三——任务加载器与预处理器

本章内容属于数据处理阶段&#xff0c;将分别介绍任务加载器task和预处理器processor。 [1] 数据集 在深入探讨数据处理的具体步骤之前&#xff0c;让我们先了解一下我们将要使用的数据集的形式。 本项目采用的是七绝数据集&#xff0c;总计83072条古诗&#xff0c;其形式如下&…

Linux系统编写C语言程序并执行(图文详解)

目录 前言 Linux如何编写C语言 1.打开编辑器&#xff0c;写代码 2.编译运行文件 相关拓展 前言 LINUX中包含了很多软件开发工具。它们中的很多是用于C和C应用程序开发的。 C是一种能在UNIX的早期就被广泛使用的通用编程语言。它最早是由Bell实验室的Dennis Ritchie为了UN…

中年人怎么发展?持续发展?

现在ai这么火&#xff0c;就像当年的xxx&#xff0c;如果没有抓住&#xff0c;会xxx吗&#xff1f; 为了ai&#xff0c;多学学python也是也是好的啊。 在学习之余&#xff0c;还是想做做自媒体的。不求马上赚到钱。我的想法是&#xff0c;现在每天下班回家都是刷刷抖音&#…