P1308 统计单词数

题目描述

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

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

输入格式

共2行。

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

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

输出格式

一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从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

总结

这该死的题,返回的位置要求的是单词首字母的位置,而不是单词的位置。错误代码错误的原因,就是返回的首字母位置是单词的位置

cin不接受空格和回车
要实行输入字符串,空格···,字符串这种形式,真的非常难。尤其还要记录你输入了多少个空格。
比如说:我下面的代码本想实现记录空格,并跳过开头的空格。但我发现,我实现不了。

	int flag_op;
	char op;
	getchar();	//用于跳过上一行输入的回车符号
	while ((op=getchar())==' ')	//用于跳过开头空格,并记录空格数
	{
		flag_op = 1;	//由于会把第一个字母给保留到op里,因此置一个开头符号
		j++;	
	}
	while (cin>>pass)	//用于输入pass
	{

		if (flag_op == 1)	//如果是开头的话,把第一个字母(存入了op,与新输入的pass串相连)
		{
			pass = op + pass;	//相连
			flag_op = 0;
		}
		char op = getchar();	//用于跳过空格,回车
		j++;	//记录跳过的空格
		if (op == '\n')
			break;
	}

本来是想如同我上述描述的一般。但是

cin>>s	它会在你用getchar跳过一个空格后,cin把剩下的空格也跳过。
		好比如,sss1    sss2  这样,j只记录一个空格,而剩下的,会被cin跳过,直接开始记录sss2
而且
在while()循环中,如果开始只有一个字母
那么,cin会把空格跳过,直接开始记录下一个s,并且会把两者相连。
你输入:u s
但,pass="us"

因此,这个方法严重不合格。

正确的代码:

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <ctype.h>
#include <stdio.h>

void strlower(char* a) 
{//手写函数,将大写字母转换成小写字母
	for (int i = 0; a[i]; i++)
	{
		if (isupper(a[i])) 
			a[i] = tolower(a[i]);//isupper是判断是否是大写字母的系统函数,tolower是将其转换成小写字母的函数
	}
}

int main() {

	char destination[1000001], * q, source[11], * p;//destintion是要找的文章,source是要找的单词,p和q都是指针类,分别代表当前搜索到什么地方了和最后一次找到单词的指针
	int flag = 0;//判断是否找到了
	int ans = 0, ans1 = -1;//个数和首次出现的位置,ans1的初值是-1是因为在没找到的时候就直接输出就行了,省事

	gets(source);
	gets(destination);//输入

	strlower(destination);//全部转换成小写字母
	strlower(source);

	int len = strlen(source);//长度,在后面防止越界和加快速度

	p = destination;//先将指针设为全部

	for (; q = strstr(p, source); ) 
	{					//循环,strstr是在一个字符串里面给定一个字符串,寻找有没有这个字符串,若有,返回首次出现的指针否则返回NULL(空指针)
		if (q != NULL	//找到了 
			&& (q == destination || *(q - 1) == ' ') //第一个条件是防止越界,第二个是判断前一个是不是空格
			&& (*(q + len) == '\0' || *(q + len) == ' ')) 
		{							//如果后面也是空格
			ans++;					//答案加一
			if (flag == 0) 
			{						//如果是首次找到
				flag = 1;
				ans1 = q - destination;//第一个位置
			}
		}
		p = q + len;//刷新指针
	}

	if (flag == 1)//找到了
		printf("%d %d", ans, ans1);//输出
	else
		printf("%d", ans1);//输出-1

	return 0;
}

下面是我自己的代码:

#include<iostream>
#include<ctype.h>
#include<stdio.h>
#include<string.h>
using namespace std;

#define MAXN 1000001

void toupper_s(char* word)	//转换大小写
{
	int i = 0;
	while (word[i] != '\0')
	{
		if (isalpha(word[i]))
		{
			word[i] = toupper(word[i]);	//在ctype.h中
		}
		i++;
	}
	return;
}

int main()
{
	char buf[MAXN];
	char word[11];
	//fgets(word, 11, stdin);	//fgets会把最后输入的回车保存到数组中的
	//fgets(buf, MAXN, stdin);
	cin.getline(word,11);
	cin.getline(buf,MAXN);
	//用cin.getline()函数更好,更佳
	toupper_s(word);
	toupper_s(buf);

	int count = 0;
	int x_point = 0;
	char* cc = buf;
	char* p;	//strstr找到源字符串中第一个子串的位置
	int len = strlen(word);

	while ((p = strstr(cc, word))!=NULL)	//找下一个位置,只要没有,立刻跳出
	{
		//当它就是第一个字符时 || 当前面一个是空格,后面一个是空格 || '\0'
		if (((((p - &buf[0]) == 0) || (*(p - 1) == ' '))) && ((*(p + len) == ' ') || (*(p + len) == '\0')))
		{
			if (count == 0)
			{
				x_point = (p - &buf[0]);
			}
			count++;
		}
		cc = p + len;	//一次加找到的位置加上word的长度
	}

	if(count!=0)
		cout << count << ' ' << x_point << endl;
	else
		cout << "-1" << endl;

	return 0;
}

对我自己代码的总结

首先
fgets(),会在你最后输入’\n’时,把’\n’也给保存到数组中。它的最后因此一般也就是’\n’’\0’。与我想要的有点不同,因此需要改变数组。
数组名是不可以改变的,因此要把数组名赋给指针,以指针改变你的定位。
strstr()找到的是第一个位置。每次找到位置之后,p=p+strlen(word),这样改变你的位置,即往后移动,可以保证不超界。

oj一般是Linux系统判题。因此对于fgets()函数而言。在Windows系统中,回车是’\r’和’\n’,而在Linux系统中,回车是’\n’
如果在Windows文件中读取Windows文件,它会把’\r’吃掉,然后才是’\n’,而在Linux下读取同样一个文件,它会忠实的先读取’\r’,然后才是’\n’。

因此。对于回车有强烈的意愿的程序要求。最好别用fgets()了。
用cin.getline(s,sizeof(s));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值