字符串的特殊读取——基于蓝桥杯两道题目(C/C++)

这篇具有很好参考价值的文章主要介绍了字符串的特殊读取——基于蓝桥杯两道题目(C/C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1  例题

1.1  卡片换位

1.2  人物相关性分析

2  字符串的读取

2.1  综述

2.2  scanf

2.3  getline/getchar/get

2.4  注意

2.5  说明

3  C语言中字符串有关问题

3.1  常用函数

3.2  使用实例

3.3  附一些函数


先看例题

1  例题

1.1  卡片换位

问题描述
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
在其中放5张牌,其中A代表关羽,B代表张飞,* 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞交换位置,其它的牌随便在哪里都可以。

输入格式:
输入两行6个字符表示当前的局面

输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
 

这道题第一眼是很难想到是一道搜索题,原因在于没有对空格进行一个正确的理解:

我们知道一个人物可以挪到空格去,但我们可以这样想,

空格也可以代表一个人物(这里将他命名为K),这个人物的特殊之处在于他可以与周围的任何一个人交换位置。

那么我们在最开始的时候就记录几个特殊点的坐标:A关羽,B张飞,K空格,就能够设置搜索的边界了

那么进行搜索时总要有一个开始点,不妨我们选择让空格主动出击,主动去和周围的人物交换,进行上下左右的尝试

每dfs一次就是对华容道阵容的一次更新

重点思路就是这样,下面看一下代码的具体实现

代码(附讲解):

#include <bits/stdc++.h>
using namespace std;
int Min=INT_MAX;//设置成最大值
struct
{
	int x,y;	
}a,b,k;//结构体定义A,B,空格坐标
int vis[3][3][3][3][3][3];//记忆化搜索
int Next[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//上下左右走

void dfs(int x1,int y1,int x2,int y2,int x,int y,int step)
{
	if(step>Min) return;//边界1,走不出去了
	if(x1==b.x&&y1==b.y&&x2==a.x&&y2==a.y)//边界2,交换完成
	{
		Min=min(step,Min);
		return;
	}
	if(x<0||x>1||y<0||y>2) return;//边界3,走出迷宫边界
	if(vis[x1][y1][x2][y2][x][y]==1) return;//边界4,已经搜索过这种情况了
	vis[x1][y1][x2][y2][x][y]=1;//开始dfs主干部分
	for(int i=0;i<4;i++)//四个方向搜索
	{
		int tx=x+Next[i][0];
		int ty=y+Next[i][1];
		if(tx==x1&&ty==y1)//空格与A交换位置
		{
			dfs(x,y,x2,y2,x1,y1,step+1);
		} 
		else if(tx==x2&&ty==y2)//空格与B交换位置
		{
			dfs(x1,y1,x,y,x2,y2,step+1);
		} 
		else//空格与*交换位置
		{
			dfs(x1,y1,x2,y2,tx,ty,step+1); 
		}
	}
	vis[x1][y1][x2][y2][x][y]=0;//回溯 
} 
 
int main()
{
 	for(int i=0;i<2;i++)
 	{
 		for(int j=0;j<3;j++)
 		{
 			char s=getchar();//字符串读取后续讲解1
			if(s=='A') 
			{
				a.x=i;
				a.y=j;
			 } 
			if(s=='B')
			{
				b.x=i;
				b.y=j;
			}
			if(s==' ')
			{
				k.x=i;
				k.y=j;
			}
		}
		getchar();//字符串读取后续讲解2
	}
	dfs(a.x,a.y,b.x,b.y,k.x,k.y,0);
	printf("%d",Min);
	return 0;
}

1.2  人物相关性分析

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
小明正在分析一本小说中的人物相关性。他想知道在小说中 Alice 和 Bob 有多少次同时出现。 更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:在小说文本 中 Alice 和 Bob 之间不超过 K 个字符。 例如以下文本: ThisisastoryaboutAliceandBob.AlicewantstosendaprivatemessagetoBob. 假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,分别是”Alice and Bob” 和”Bob. Alice”。前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。 注意: 1. Alice 和 Bob 是大小写敏感的,alice 或 bob 等并不计算在内。 2. Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能 有字母。例如 Bobbi 並不算出现了 Bob。
【输入格式】
第一行包含一个整数 K。 第二行包含一行字符串,只包含大小写字母、标点符号和空格。长度不超 过 1000000。
【输出格式】
输出一个整数,表示 Alice 和 Bob 同时出现的次数。
 

这道题主要考察对细节的处理和对字符串的读取。

首先需要读取这个字符串,关于这个字符串的读取放到后面讲解

然后就是要计算出符合条件的Alice和Bob所在的位置,注意这里的符合条件是指Alice和Bob后面一个字符不是字母(根据常识前面一位不可能是字母)

最后遍历Alice数组,采用双指针法维护Bob动态窗口(反过来也可),找出符合条件的区间,记录答案

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

int main() 
{
    ios::sync_with_stdio(false);
    int k;
    string s;
    ll ans=0;
    cin >> k;
    cin.get();//字符串读取后续讲解3 
    getline(cin, s);//字符串读取后续讲解4

    vector<ll>Alice,Bob;
    for (ll i = 0; i < s.size();) 
    {
        if (s.substr(i, 5) == "Alice") 
        {
            if (i - 1 >= 0 && isalpha(s[i - 1]) || i + 5 < s.size() && isalpha(s[i + 5]))//不满足条件的情况 字符串读取后续讲解5
                continue;
            Alice.push_back(i);
          
            i += 5;
        } 
        else if (s.substr(i, 3) == "Bob") 
        {
            if (i - 1 >= 0 && isalpha(s[i - 1]) || i + 3 < s.size() && isalpha(s[i + 3]))//不满足条件的情况
                continue;
            Bob.push_back(i);
            
            i += 3;
        } 
        else i++;
    }
    for(ll i = 0,l=0,r=0; i < Alice.size(); i++)
    {  //遍历Alice数组元素 
        while(l < Bob.size() && Bob[l] <  Alice[i] - k - 3)    l++;   //维护窗口左边界 
        while(r < Bob.size() && Bob[r] < Alice[i] + k + 5)   r++;   //维护窗口右边界 
        ans += r - l;             //答案加上窗口中元素个数 
    }
    cout<<ans;
    return 0;
}

遍历Alice数组那一部分-k-3和+k+5的原因是:

我们记录的Alice和Bob的位置指的是记录A和B的位置(即首字母的位置),如果Alice在Bob前面,Alice和Bob之间空了k个字符,那么A和B之间空了(k+5)个字符。同理,如果Alice在Bob前面,Alice和Bob之间空了k个字符,那么A和B之间空了(k+3)个字符。

另外,left指针遇到符合条件的值就不再移动,所以left指针最终指向的是不符合条件的值。

right指针遇到不符合条件的值就不再移动,所以right指针最终指向的是符合条件的值

窗口的左边界是不可取的值,窗口的右边界是可取的值,即符合条件的范围是(left,right],所以ans计算方式如上

2  字符串的读取

2.1  综述

由上面两道题,我们可以发现学好字符串的读取和原理还是很有必要的

字符串或字符的输入有好多个函数,scanf、getline()、cin.getline()、cin.get()、gets()、getchar()等

先得出大致结论:

如果输入是不带空格的字符串,那用什么都可以了,建议用scanf或cin(最好用scanf,因为scanf的读取比cin快,同理printf的读取比cout快)

如果输入带空格,那scanf、cin就用不了了,可以考虑以下方法:
如果想用string类型的话,就用getline(cin, s)
如果想用字符数组类型的话,可以用**cin.getline()、cin.get()、gets(),**这里不是特别建议用gets(),因为这个函数可能会出点奇怪的问题,也不建议用cin.get(), 因为这个函数既不能忽略缓冲区的换行符,还不能在输入后抹掉自己的结束符,建议使用cin.getline()
如果输入的时候是单个字符,或者只想要字符串的第一个字符,就可以用getchar()、cin.get()
下面进行具体的讲解:

2.2  scanf

scanf用于字符串数组,遇到空格或换行就停止

char str[10];
scanf("%s", str);
cout<<str<<endl;

2.3  getline/getchar/get

可以接受空格,读取时遇到换行符结束

getline有两种读取方法,法一是string流,法二是iostream流,是两个不一样的函数

方法一:(这里还是建议用方法一)

使用string

string str;
getline(cin, str);
cout<<str<<endl;

方法二:

使用字符串数组

char str[100];
cin.getline(str, 20, '\n')
//cin.getline()里面三个参数,第一个是要储存的字符串数组,第二个是最大长度 + 1,最后一个位置用来存储'\0',也就是说你填20,但是只能存前19个字符,第三个是结束符,可省略,默认是换行符

getchar一次只能读取一个字符

2.4  注意


程序的输入都建有一个缓冲区,每次输入的过程,其实是计算机先将输入的数据存在输入缓冲区中,而我们使用的输入函数是直接从缓冲区中读取数据。使用cin的时候,遇到空格和换行符和tab键就会停止,此时缓冲区就会有残留数据:空格、换行符、tab。cin和cin.get()从缓冲区读入的时候会自动忽略第一个空格、换行符、tab,就可以正常读入字符串,但有些函数并不能,比如 getline,gets,get, 他们就会直接读取缓冲区剩余的空格、换行符、tab,就导致需要输入的输不进去。

所以如果你使用getline()或gets()或者cin.get()之前用了cin或cin.get(),请务必在cin后面加个getchar();
概括一下:

scanf和cin这类输入的方法不能记录空格、换行、tab的信息,所以这两种输入方法对空格、换行、tab很敏感,他们一遇到空格、换行、tab就只能中止读取(在一开头就空格、换行、tab直接无视),并且空格、换行、tab的字符并不能从缓冲区带走,导致缓冲区有残余,如果这个时候再用get一类的函数,就会出问题

举例:

string s;

cin>>s;

假设我们输入了abcdefg,为了结束输入,我们换行

此时计算机认为我们输入了abcdefg\n,然后abcdefg离开缓冲区,\n残留在缓冲区,如果下一步继续用get等函数,就会直接读取\n,出现错误

get这类函数对空格、换行、tab不敏感,把空格、换行、tab同样当做字符读取,在换行之后,同样地\n留在缓冲区,再用读取函数容易导致错误

所以get这种函数最常见的应用就是吃字符

字符串的特殊读取——基于蓝桥杯两道题目(C/C++)

 比如例题2的读取华容道,我们在输入每一个信息之后都会有空格或者换行代表输入的中止,为了消除这个中止字符对后续读取的影响,我们要加一个getchar()或者getline()把中止字符吃掉

如果你看懂了前面的说明,那么这个时候你就可以知道:

用cin/scanf之后不能盲目用getchar/getline/get,如果要用,就要在cin后吃字符

用getchar/getline/get之后可以用cin/scanf

2.5  说明

其实很多时候,我们是不用刻意关心字符的精读这个问题的

只有在题目要求需要读取空格等特殊字符时我们再进一步考虑

3  C语言中字符串有关问题

3.1  常用函数

strlen(字符串名):测定字符串长度

gets(字符串名):读取字符串

strcat(字符串1,字符串2):将字符串2接在字符串1后面

strncat(字符串1,字符串2,最多拼接字母数):将字符串2接在字符串1后面,最多拼接字符数有限制

strcpy(字符串1,字符串2):把字符串2拷贝给字符串1

strncpy(字符串1,字符串2,最多拷贝字符串):把字符串2拷贝给字符串1,最多拼接字符数有限制

3.2  使用实例

例子:字符串中单词数量(两种写法)

#include <bits/stdc++.h>
using namespace std;
char str[100];
int i=0,cnt=0;

int main()
{
	gets(str);
	/*if(str[0]>='a'&&str[0]<='z'||str[0]>='A'&&str[0]<='Z') cnt++; 
	for(i=1;i<strlen(str)-1;i++)
	{
		if(str[i]==' ')
		{
			if(str[i+1]>='a'&&str[i+1]<='z'||str[i+1]>='A'&&str[i+1]<='Z') cnt++; 
		}
	}*/
	if(isalpha(str[0])) cnt++; 
	for(i=1;i<strlen(str)-1;i++)
	{
		if(str[i]==' ')
		{
			if(isalpha(str[i+1])) cnt++; 
		}
	}
	printf("%d",cnt);
	return 0;
} 

例子:字符串拼接

#include <stdio.h>
#include <string.h>
char a[100],b[100];

int main()
{
	gets(a);
	gets(b);
	strcat(a,b);
	puts(a);
	strncat(a,b,10);
	puts(a);
	return 0; 
}

例子:字符串比较函数返回值

#include <stdio.h>
#include <string.h>
char a[100],b[100];

int main()
{
	gets(a);
	gets(b);
	printf("%d ",strcmp(a,b));
	printf("%d",strcmp(b,a));
	return 0;
}

例子:比较三个字符串的大小

#include <stdio.h>
#include <string.h>
char str1[100],str2[100],str3[100],str[100];
int main()
{
	gets(str1);
	gets(str2);
	gets(str3);
	if(strcmp(str1,str2)>0) strcpy(str,str1);//如果字符串1大于字符串2,则暂存字符串1 
	else strcpy(str,str2);//否则,暂存字符串2 
	if(strcmp(str3,str)>0) strcpy(str,str3);//如果字符串大于暂存,3是最大的 
	printf("%s",str);//否则,string是最大的 
	return 0;
}

3.3  附一些函数

1.判断是否是字母

isalpha(),若是返回true,否则返回false

2.判断是否是数字

isdigit(),若是返回true,否则返回false

3.判断是否是大写字母

isupper(),  若是返回true,否则返回false;

4.判断是否是小写字母

islower(),若是返回true,否则返回false;

5.大写转化为小写字母

tolower()

6.小写转化为大写字母

toupper()
 文章来源地址https://www.toymoban.com/news/detail-419549.html

到了这里,关于字符串的特殊读取——基于蓝桥杯两道题目(C/C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# 字符串操作指南:长度、连接、插值、特殊字符和实用方法

    字符串用于存储文本。一个字符串变量包含由双引号括起的字符集合 示例: 如果需要,一个字符串变量可以包含多个单词: 示例: 在 C# 中,字符串实际上是一个对象,其中包含可以在字符串上执行某些操作的属性和方法。例如,可以使用 Length 属性找到字符串的长度: 示例

    2024年01月20日
    浏览(29)
  • C语言【几个关于字符串/字符的函数的使用、几个特殊的++】

    关于++,编译器会作一些处理(根据编译器不同),如下为gcc编译出来的结果:

    2024年02月05日
    浏览(34)
  • 蓝桥杯单片机 ——接收字符、字符串

     1定时器中断方法 (完整代码在文末!!)  2.定时的方法(推荐): 蓝桥杯单片机第十四届第三次模拟题_让我来瞅一瞅的博客-CSDN博客 定时器0——定时功能        判断接受数据是否完成  定时器1——串口功能           接受、发送数据   1.接受、发送 均为文本模式

    2023年04月17日
    浏览(31)
  • 蓝桥杯 java 重复字符串

    2024年01月18日
    浏览(26)
  • 整理mongodb文档:集合名字有类似-等特殊字符串如何处理?

    整理mongodb文档:集合名字有类似-等特殊字符串如何处理? 首先,先创建一个collection的名字为’collection-test’,这个表名中,colletion的名字有一个特殊字符串“-”,但是后面插入数据的时候会有这么一个错误返回 很多情况下,我们的表名会有类似-或则是/等这些特殊字符串,

    2024年02月14日
    浏览(30)
  • 【蓝桥杯算法题】字符串匹配算法

    这段代码实现了一个过滤字符串中非字母字符的功能,并统计字母个数。 首先,在主函数中,定义一个长度为100的字符数组str,用fgets函数从标准输入获取用户输入的字符串。 然后调用filterLetters函数,利用指针p1和p2遍历字符串中的每个字符,判断是否为字母字符, 若是,则

    2024年02月08日
    浏览(35)
  • (蓝桥杯每日一题)字符串排序

    本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 小蓝要把一个字符串中的字母按其在字母表中的顺序排列 例如,LANQIAO 排列后为AAILNOQ 又如, GOODGOODSTUDYDAYDAYUP 排后为AADDDDDGGOOOOPSTUUYYY 请问对于以下字符串,排列之后字符串是什么? WHERETHEREISA

    2024年01月21日
    浏览(27)
  • c++读取字符串字符时出错

    这是我做的一个c++爬虫程序但是在抓取网页的时候string类型传递出现了问题 以下是图片代码  url的值是 \\\"http://desk.zol.com.cn/\\\" 我不知道为什么数据传递会出问题 请大佬指教 后面重新启动一遍编译器查一查断点有突然没问题了 ,真是个玄学的问题。我还以为是mallco出问题了

    2024年02月12日
    浏览(34)
  • 【数据结构】数组和字符串(二):特殊矩阵的压缩存储:对角矩阵——一维数组

    【数据结构】数组和字符串(一):矩阵的数组表示   矩阵是以按行优先次序将所有矩阵元素存放在一个一维数组中。但是对于特殊矩阵,如对称矩阵、三角矩阵、对角矩阵和稀疏矩阵等, 如果用这种方式存储,会出现大量存储空间存放重复信息或零元素的情况,这样会造

    2024年02月08日
    浏览(37)
  • 【数据结构】数组和字符串(四):特殊矩阵的压缩存储:稀疏矩阵——三元组表

    【数据结构】数组和字符串(一):矩阵的数组表示   矩阵是以按行优先次序将所有矩阵元素存放在一个一维数组中。但是对于特殊矩阵,如对称矩阵、三角矩阵、对角矩阵和稀疏矩阵等, 如果用这种方式存储,会出现大量存储空间存放重复信息或零元素的情况,这样会造

    2024年02月05日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包