洛谷 P1308 统计单词数 字符串处理

洛谷 P1308 统计单词数

题目描述
一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。

现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 )。

输入格式
共22行。

第11行为一个字符串,其中只含字母,表示给定单词;

第22行为一个字符串,其中只可能包含字母和空格,表示给定的文章。

输出格式
一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从00 开始);如果单词在文章中没有出现,则直接输出一个整数-1−1。

输入输出样例
输入 #1
To
to be or not to be is a question
输出 #1
2 0

输入 #2
to
Did the Ottoman Empire lose its power at that time
输出 #2
-1


分析

明显的一道字符串处理题目, 惯例先贴代码后说细节


代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
using namespace std;

char a[20];
char b[1000010];
//string a;
//string b;

int main(void)
{
	int cnt = 0;
	int first;
//	getline(cin,a);
//	getline(cin,b);
	scanf("%[^\n]", a);
	getchar();
	scanf("%[^\n]", b);
	getchar();
	
	int a1 = strlen(a);		//TLE补救措施
	int b1 = strlen(b); 	//成功了!! 
	
	for( int i=0; i<a1; i++)
	{
		a[i] = tolower(a[i]);
	}
	for( int i=0; i<b1; i++)
	{
		b[i] = tolower(b[i]);
	}	
	
	
	
	for( int i=0; i<b1; i++)
	{
		if( b[i]==a[0])
		{
			int j=0;
			if( strncmp(&b[i], a, a1)==0 )
			{
				if((i==0 && b[i+a1]==' ') || (b[i-1]==' ' && b[i+a1]==' ') || (b[i-1]==' ' && b[i+a1]=='\0'))
				{
					cnt ++;
					if( cnt==1)
					{
						first = i;
					}
					i += a1;					
				} 
			}
		}
	}
	if( !cnt)
	{
		printf("-1");
	}
	else
	{
		printf("%d %d", cnt, first);
	}
	return 0;
}

收获与反思

  1. 首先, 本题的第一个问题出现在了输入部分. 之前在紫书上看到两个关于字符串输入的函数, 分别为fgetc(fin)和fgets(buf, maxn, fin). 暂时不理解这两个函数是如何使用的(大概和文件相关吧). 因此本题进行了两个输入尝试.
    (1). getline()函数
    该函数似乎要用一种string a的方式定义的字符串才有效, 刚入C++, 还不太熟悉这方面的用法, 因此作废(日后学到C++再考虑把该版本重新做一遍)
    (2). scanf()函数
    仍然用最传统的scanf, 特殊的是scanf("%[^\n]", a), 其中[^ ]内的内容是遇到其后的数据便停止输入. 只是要注意再其后加一个getchar(), 把末尾的\n"吸"掉
  2. 刚在紫书上看过<ctype.h>库的内容就用上了, 本题因为不区分大小写, 使用该库中的tolower()函数将大写字母全部转换为小写字母(该函数应该(?)只能将单个字符转换) 另外, 该库中其他有用的函数如下:
    (1). isalpha() 判断是否为字母
    (2). isdigit() 判断是否为十进制数
    (3). isprint() 判断是否为可打印字符, 包括空格 (突发奇想, 是否可以用该函数来输入一个英文段落?)
    (4). tolower(), toupper(), 大小写两兄弟
  3. 该题中一个很有趣的尝试是使用了strncmp()函数, 并取的是b字符串的中间一部分与a字符串比较, 具体方法就是将要比较的首字母地址交给strncmp的第一个变量, a给第二个, 再把strlen(a)交给第三个变量. 居然成功了. 由此可见, 大部分对字符串的操作, 实际就是对该字符串首地址的操作, 而大部分与字符串相关的函数理论上都可以取地址后对一部分进行操作.
  4. 该题第一次提交的时候tle了, 在意料之内, 之后将题干中另设置了两个变量来保存a, b的字符串长度, 代替了代码中无数个strlen(), 果不其然, 运行时间缩短了十几倍, 教训就是在循环语句中, 或者在程序中需要多次用到一个函数时, 单独设置一个变量来保存该函数的值, 而不要重复使用它
  5. 该题目要求是从字符串b中找字符串a出现的首位置和次数, 第一反应是使用strstr()函数, 但想起来该函数的返回值是发现a字符串的首地址, 而不能返回次数, 所以放弃了该想法. 但做完之后查看题解, 发现一个使用指针的做法中, 每次讲不同的地址赋给strstr()函数的第一个变量, 该方法与如上的第3点类似. 之后可以由此尝试一下.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值