第3天----在一行句子中寻找最长最短单词

今天我们将学习如何在一行句子中寻找(第一次出现的)最长最短单词。本节内容会或多或少地利用到第一讲/第二讲的知识点,需要的同学可以先去看看前面的内容。

在这里插入图片描述


一、小试牛刀:

题目描述
输入 1 行句子(不多于 200 个单词,每个单词长度不超过 100),只包含字母、空格、逗号和句号。单词由至少一个连续的字母构成,空格、逗号和句号都是单词间的间隔。
输出第 1 个最长的单词和第 1 个最短单词。

输入格式
输入数据:一行句子。

输出格式
输出数据:

  • 第 1 行,第一个最长的单词。
  • 第 2 行,第一个最短的单词。

输入输出样例
输入:
I am a student,i am studying Programming language C in Peking University.
输出:
Programming
I

  • 根据题目要求,我们只需要在所有合法的字符串中,输出第一个出现的最长单词和最短单词。

1. 方法一:

  • 我们可以对于每个读入的字符串利用C++string库里的find()函数查找目标字符','/'.'是否存在,并利用substr()函数来截取所需的字符串(goto可以解决连续逗号问题),最后将所有合法的字符串存储到vector容器中。具体代码如下:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<string>str;//存储字符串
vector<int>str_length;//存储字符串长度
string s, s1;
size_t found;//用于find函数

int main(void)
{	
	int cnt = 0;//字符串个数
	while (1)
	{
		cin >> s;
		loop:
		found = s.find(',');//在s中查找逗号是否存在
		if (found != string::npos)//如果找到了逗号
		{
			s1 = s.substr(0, found);//0~found截取字符串

			str.push_back(s1);//将截取的字符串存入str
			str_length.push_back(s1.length());//将截取的字符串长度存入str_length
			cnt++;

			s = s.substr(found + 1);//将s截取为逗号后面的字符串
			goto loop;//为了避免逗号连续出现,所以用goto返回到loop继续判断
		}
		if (s[s.length() - 1] == '.') {//如果该字符最后一个字符是句号
			s1=s.substr(0, s.length() - 1);//截取句号前面的字符串

			str.push_back(s1);
			str_length.push_back(s1.length());
			cnt++;

			break;
		}

		str.push_back(s);
		str_length.push_back(s.length());
		cnt++;
	}
	int max = 0;
	int min = 0;
	for (int i = 0; i < cnt; i++)
	{
		if(str_length[i]>str_length[max])  max = i;
		if(str_length[i]< str_length[min]) min = i;
		//cout << str[i] << " ";//print大法
	}
	cout << str[max] << endl;
	cout << str[min];

	return 0;
}
  • 此方法虽然容易想,但是本身的执行效率并不高,时间复杂度和空间复杂度占用较大。

2. 方法二:

相信大家拿到这题后很快就可以想出来,我们需要发现一个单词,在单词中间记录信息,再对比信息。

  • 那么怎样判断一个单词的开始与结束呢?

我们在阅读的时候,每个单词开始前都会有一个标点符号或空格提醒我们这是下一个单词,那么代码也一样,发现一个空格或标点符号,更新数据。

for(int i=0;i<a.length();i++){
	if(a[i] == ' ' || a[i] == ',' || a[i] == '.'){
		//更新数据;	
	}
   	//单词长度++;
}
  • 如何更新数据?

可以设置两个变量,一个记录最长单词的结束位置,一个记录最长单词的长度,这样输出时我们就可以用结束位置-长度找到开始位置,并且输出。最小值也一样。

  • 具体代码如下:
#include <iostream>
#include <string>
using namespace std;
string a;
int sum = 0, maxx = -100, maxb, minb, minn = 1000000;
int main() {
	getline(cin, a);//带空格输入
	for (int i = 0; i < a.length(); i++) {
		if (a[i] == ' ' || a[i] == ',' || a[i] == '.') {//如果发现标点符号和空格,代表单词结束
			if (maxx < sum) {//如果单词长度突破目前发现的最长长度
				maxb = i;//把最长单词的结束点更新,i就是结束点
				maxx = sum;//把最长单词的长度更新
			}
			if (minn > sum) {//如果单词长度低于目前发现的最短长度
				minb = i;//更新最短单词结束点
				minn = sum;//更新最短长度
			}
			sum = 0;//sum清空,以便下次操作
		}
		else {
			sum++;//如果是字母,长度加一
		}
	}
	for (int i = maxb - maxx/*从开始位置开始输出*/; i < maxb/*到结束位置结束*/; i++) {
		cout << a[i];
	}
	cout << endl;
	for (int i = minb - minn; i < minb; i++) {//最短单词同理
		cout << a[i];
	}
	return 0;
}
  • 这样做可谓是非常妙,时间复杂度和空间复杂度大大降低,极大地提高了代码的运行效率,并且撇弃了复杂的操作,不仅更易书写,也使读者更易理解。

3. 方法三:

  • 每个字符逐个读入,读取到换行或文件结束时退出。先判断是不是分隔符,如果是,就更新最长单词和最短单词,并清空当前单词,否则添加当前字符到当前单词里。最后输出结果就可以了。代码如下:
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
	string a,b,t;
	int la=0,lb=1000;
	char ch;
	while(ch=getchar())
	{
		if(ch=='\n'||ch==EOF)	break;
		if(ch==' '||ch==','||ch=='.')
		{
			if(t.length()>la)
				a=t,la=t.length();
			if(t.length()<lb)
				b=t,lb=t.length();
			t="";
			continue;
		}
		t.push_back(ch);
	}
	cout<<a<<endl<<b;
	return 0;
}
  • 其实方法3本身和方法2并没有太大的区别,但相较于方法2来说则更为简便,对于结果的输出不再是利用做差得到,而是直接输出,使得代码进一步优化。

4. 方法四:

  • 在这题中,我们需要得出句中最长的单词与最短的单词。因此,我们可以采用 string 字符串 的方式进行扫描。首先是整体的字符串 s ,要使用 getline 进行输入,因为 字符串中有空格。然后是单词的字符串 s0 ,同时需要计数(单词长度),再与 ans1 , ans2 打擂台得到最大值与最小值。
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int ans1=0,ans2=0x3f3f3f,cnt;
string s,s1,s2,s0;
int main()
{
	getline(cin,s);//一整行输入
	for(int i=0;i<s.length();i++)
	{
		if(s[i]==' '||s[i]==','||s[i]=='.')//判定单词末尾(注意中英符号区分)
		{
			if(cnt>ans1)//最大值打擂台
			{
				s1=s0;
				ans1=cnt;
			}
			if(cnt<ans2)//最小值打擂台
			{
				s2=s0;
				ans2=cnt;
			}
			cnt=0;
			s0.clear();//清除当前单词
		}
		else
                {
                    s0+=s[i]; //一般情况(记录单词字母以及其个数)
                    cnt+=1;
                }
     	
	}
	cout<<s1<<endl<<s2<<endl;//一般输出
    return 0;
}

  • 此方法和方法2,3类似,不做过多解释。

二、拓展讲解:

1.substr()函数:

  • C++substr()函数是用于提取字符串的子串的函数。它接受两个参数,第一个参数是起始位置,第二个参数是要提取的子串的长度。函数返回一个新的字符串,包含从起始位置开始的指定长度的字符。

下面是substr()函数的语法:

string substr (size_t pos, size_t len) const;
  • pos:起始位置,表示要提取子串的起始字符的索引。索引从0开始计数
  • len:子串的长度,表示要提取的字符数量。

下面是一个示例代码,演示如何使用substr()函数:

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello,World!";
    
    // 提取从索引6开始的子串,长度为5
    std::string sub = str.substr(6, 5);
    
    std::cout << sub << std::endl; // 输出 "World"
    
    return 0;
}

在上面的示例中,我们首先定义了一个字符串str,然后使用substr()函数提取了从索引6开始的子串,长度为5。提取的子串存储在变量sub中,并打印输出。

  • 需要注意的是,substr()函数返回的是一个新的字符串,不会修改原始字符串

当然,在C++中,substr()函数也可以只传递一个参数,表示从指定位置开始提取到字符串的末尾的子串。

  • 下面是一个示例代码,演示如何使用只有一个参数的substr()函数:
#include <iostream>
#include <string>

int main() {
    std::string str = "Hello,World!";
    
    // 提取从索引7开始到字符串末尾的子串
    std::string sub = str.substr(6);
    
    std::cout << sub << std::endl; // 输出 "World!"
    
    return 0;
}
  • 在上面的示例中,我们使用substr()函数只传递了一个参数,即起始位置。这将提取从索引6开始到字符串末尾的子串,并将其存储在变量sub中,然后打印输出。

2. goto语句:

  • C语言中的goto语句是一种无条件跳转语句,它可以将程序的执行直接转移到指定的标签位置。goto语句可以用于跳转到程序中的任意位置,包括循环、条件语句、函数等。

下面是goto语句的基本语法:

goto label;
...
label: statement;
  • goto后面是标志符label,它是用户定义的标签(标签名称必须是唯一);
  • 将标签放在需要跳转执行的地方前面且以冒号:结尾。
  • label后面是一个语句,该语句是在goto语句被执行时要跳转到的位置。

下面是一个使用goto语句的示例代码:

#include <stdio.h>

int main() {
    int i = 1;
    
    loop:
    printf("i = %d\n", i);
    i++;
    
    if (i <= 5) {
        goto loop; // 跳转到标签loop处
    }
    
    return 0;
}
  • 在上面的示例中,我们使用goto语句在循环中实现了一个简单的计数器。首先定义了变量i并初始化为1,然后使用loop作为标签。在循环中,我们打印输出i的值,然后将i递增。如果i小于等于5,就跳转到标签loop处继续执行循环。这样,我们就实现了一个简单的计数器。

但需要注意的是,goto语句容易导致程序结构混乱,使代码难以理解和维护。因此,在实际编程中,应尽量避免使用goto语句,而是使用更结构化的控制流语句(如循环和条件语句)来组织代码。


3. string::clear()函数:

  • 在C++的string库中,clear()函数用于清空字符串的内容,即将字符串中的所有字符都删除,使字符串变为空字符串。

下面是clear()函数的语法:

void clear();
  • clear()函数没有参数。
  • 调用clear()函数将清空字符串的内容。

下面是一个使用clear()函数的示例代码:

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello, World!";
    
    std::cout << "Before clear: " << str << std::endl; // 输出 "Before clear: Hello, World!"
    
    str.clear();
    
    std::cout << "After clear: " << str << std::endl; // 输出 "After clear: "
    
    return 0;
}
  • 在上面的示例中,我们首先定义了一个字符串str,并将其初始化为"Hello, World!"。然后,我们使用clear()函数清空了字符串的内容。在调用clear()函数后,字符串变为空字符串。最后,我们通过打印输出来验证字符串是否已经清空。

但需要注意的是,clear()函数只清空字符串的内容,而不会释放字符串所占用的内存。字符串对象的容量(即分配的内存大小)不会改变。如果需要释放字符串所占用的内存,可以使用shrink_to_fit()函数。


4. shrink_to_fit()函数:

  • 在C++的string库中,shrink_to_fit()函数用于将字符串的容量调整为适合其当前大小的最小值。这意味着它可能会释放字符串中未使用的内存空间,从而减少内存的占用

下面是shrink_to_fit()函数的语法:

void shrink_to_fit();
  • shrink_to_fit()函数没有参数。
  • 调用shrink_to_fit()函数将使字符串的容量调整为适合其当前大小的最小值。

下面是一个使用shrink_to_fit()函数的示例代码:

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello, World!";
    
    std::cout << "Before shrink_to_fit: capacity = " << str.capacity() << std::endl; // 输出 "Before shrink_to_fit: capacity = 14"maybe
    
    str.shrink_to_fit();
    
    std::cout << "After shrink_to_fit: capacity = " << str.capacity() << std::endl; // 输出 "After shrink_to_fit: capacity = 13"maybe
    
    return 0;
}
  • 在上面的示例中,我们首先定义了一个字符串str,并将其初始化为"Hello, World!"。然后,我们使用capacity()函数获取字符串的容量,并打印输出。在调用shrink_to_fit()函数后,我们再次使用capacity()函数获取字符串的容量,并打印输出。可以看到,调用shrink_to_fit()函数后,字符串的容量可能会从14减少到了13,即可能会释放1个字节的内存空间。
  • 但需要注意的是,根据C++标准,shrink_to_fit()函数是一个非强制性的操作,实现可能会忽略该请求。因此,调用shrink_to_fit()函数并不一定会导致字符串的容量减小。

  • 实际上,大多数实现中的string类会动态地管理内存,根据需要自动分配和释放内存。当我们从字符串中删除字符时,实现通常会自动释放相应的内存,而不需要显式调用shrink_to_fit()函>数。


  • 本节我们主要学习了如何在一个句子中找到并打印出第一个出现的最长单词,用了几种不同的方法去实现,但是殊途同归,基本的思路是一致的。除此之外,我们还学习了substr()函数,goto语句,clear()函数等等。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring学习笔记+SpringMvc+SpringBoot学习笔记

壹、核心概念&#xff1a; 1.1. IOC和DI IOC&#xff08;Inversion of Control&#xff09;控制反转&#xff1a;对象的创建控制权由程序转移到外部&#xff0c;这种思想称为控制反转。/使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程种对象…

[四次挥手]TCP四次挥手握手由入门到精通(知识精讲)

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

人工智能与云计算实训室建设方案

一、 人工智能与云计算系统概述 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一种模拟人类智能的科学和工程&#xff0c;通过使用计算机系统来模拟、扩展和增强人类的智能能力。人工智能涉及多个领域&#xff0c;包括机器学习、深度学习、自然…

mysql的两张表left join 进行关联后,索引进行优化案例

一 mysql的案例 1.1 不加索引情况 1.表1没加索引 2.表2没加索引 3.查看索引 1.2 添加索引 1.表1添加索引 2.表2添加索引 3.查看

使用navicat连接postgresql报错问题解决

使用navicat连接postgresql报错问题解决 一、问题现象&#xff1a; 最近使用Navicat来连接postgreSQL数据库&#xff0c;发现连接不上&#xff0c;报错信息如下&#xff1a; 自己百度了一下&#xff0c;发现pgsql 15版本以后&#xff0c;有些系统表的列名改了&#xff0c;pg_…

一文科普,配资门户网是什么?

配资门户网是一个为投资者提供配资服务的平台。配资是指通过借用他人资金进行投资交易的一种金融操作方式。配资门户网作为一个线上平台&#xff0c;为投资者提供了方便、快捷的配资服务。 配资门户网提供了多种不同的配资方案&#xff0c;以满足不同投资者的需求。投资者可以…

录制游戏视频的软件有哪些?分享3款软件!

“有录制游戏视频的软件推荐吗&#xff1f;最近迷上了网游&#xff0c;想录制点自己高端操作的游戏画面&#xff0c;但是不知道用什么软件录屏比较好&#xff0c;就想问问大家&#xff0c;有没有好用的录制游戏视频软件。” 在游戏领域&#xff0c;玩家们喜欢通过录制游戏视频…

根据源码,模拟实现 RabbitMQ - 实现消息持久化,统一硬盘操作(3)

目录 一、实现消息持久化 1.1、消息的存储设定 1.1.1、存储方式 1.1.2、存储格式约定 1.1.3、queue_data.txt 文件内容 1.1.4、queue_stat.txt 文件内容 1.2、实现 MessageFileManager 类 1.2.1、设计目录结构和文件格式 1.2.2、实现消息的写入 1.2.3、实现消息的删除…

HCIP实验之MPLS

目录 一&#xff0c;实验题目 ​编辑 拓扑与IP地址规划如图所示 二&#xff0c;实验思路 三&#xff0c;实验步骤 3.1 私网部分IP地址配置 3.2 LSP部分配置 3.3 启动OSPF协议 3.4 启动MPLS协议 3.5 启动MPLS VPN 3.6 实现公网私网互通 3.7 配置BGP 3.8 双向重发布 …

常见的 Python 错误及其解决方案

此文整理了一些常见的 Python 错误及其解决方案。 1、SyntaxError: invalid syntax 说明&#xff1a;无效的语法是最常见的错误之一&#xff0c;通常是由于编写代码时违反了 Python 的语法规则。可能的原因&#xff1a; 忘记在 if、while、for 等语句后写冒号&#xff0c;或者…

我和 TiDB 的故事 | 远近高低各不同

作者&#xff1a; ShawnYan 原文来源&#xff1a; https://tidb.net/blog/b41a02e6 Hi, TiDB, Again! 书接上回&#xff0c; 《我和 TiDB 的故事 | 横看成岭侧成峰》 &#xff0c;一年时光如白驹过隙&#xff0c;这一年我好似在 TiDB 上投入的时间总量不是很多&#xff0…

vite打包配置以及性能优化

vite打包配置以及性能优化 安装插件 首先该安装的插件&#xff0c;你要安装一下吧 这三个是基本的插件&#xff0c;其他优化的插件下面会介绍到 "vite": "4.4.6","vite-plugin-html": "^3.2.0","vitejs/plugin-vue": &qu…

Eureka:集群环境配置

创建三个集群 导包 <!-- 导包--><dependencies><!-- Eureka -server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka-server</artifactId><version>1.…

信号

信号也是IPC中的一种&#xff0c;是和管道&#xff0c;消息队列&#xff0c;共享内存并列的概念。 本文参考&#xff1a; Linux中的信号_linux中信号_wolf鬼刀的博客-CSDN博客 Linux系统编程&#xff08;信号处理 sigacation函数和sigqueue函数 )_花落已飘的博客-CSDN博客 Linu…

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…

Scratch 之 RPG 引擎制作教程(1) / 地图行走

大家好&#xff0c;又和大家见面了&#xff0c;那么我们这期讲的就是RPG游戏的地图以及人物的行走。 我发现大家并不是很懂RPG游戏引擎&#xff0c;也就是说这种引擎对于技术的要求还是比较高的。为了让更多人直接上手制作RPG游戏&#xff0c;我打算开启这一系列教程。 这个教程…

Azure应用程序网关

文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务&#xff0c;用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…

Cesium加载Supermap的wmts服务

最近使用cesium 加载supermap的wmts 服务&#xff0c;多次遇到加载异常与白页面问题&#xff0c;纠结好久最后才搞定[特此记录] 1、首先找到方法加载wmts 的api 文档 官方提示使用WebMapTileServiceImageryProvider加载wmts 2、然后编辑加载代码 //1.新建ImageryProviderlet…

【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 serde app.rs中首先定义了我们的Templ…

Three.js程序化3D城市建模【OpenStreetMap】

对于我在 Howest 的研究项目&#xff0c;我决定构建一个 3D 版本的 Lucas Bebber 的“交互式讲故事的动画地图路径”项目。 我将使用 OSM 中的矢量轮廓来挤出建筑物的形状并将它们添加到 3js 场景中&#xff0c;随后我将对其进行动画处理 推荐&#xff1a;用 NSDT编辑器 快速搭…