第37次CCF第三题--模板展开--stringstream读取字符串

1 a hello
1 b world
2 c $a $b
1 d good $c
1 a hi
1 e good $c

 

1 a hello
1 b world
2 c $a $b
3 c
1 a hi
3 c

将会输出:10 和 7,对应的变量的值为:

helloworld
hiworld

需要注意的是,在使用间接赋值语句时,在变量的值之间建立了依赖关系,在上述模板中,变量 c 的值依赖于变量 a 和 b 的值。 可以想见,如果变量的值间的依赖关系形成了环,那么模板将无法执行。我们约定,给定的表达式中不存在这样的环。

形式化地,模板语言用 BNF 表示如下:

CHAR ::= [a-z0-9]
SPACE ::= ' '
DOLLAR ::= '$'
NONEMPTY_STRING ::= CHAR | NONEMPTY_STRING CHAR
STRING ::= '' | NONEMPTY_STRING
VAR ::= NONEMPTY_STRING
OPERAND ::= DOLLAR VAR | NONEMPTY_STRING
EXPR ::= OPERAND | EXPR SPACE OPERAND
ASSIGN_OP ::= '1' | '2'
ASSIGN ::= ASSIGN_OP SPACE VAR SPACE EXPR
OUTPUT ::= '3' SPACE VAR
STATEMENT ::= ASSIGN | OUTPUT

输入格式

从标准输入读入数据。

输入的第一行为一个整数 nn,表示模板语言的语句数量。接下来的 nn 行,每行为一个语句,语句的格式如上所述。

输出格式

输出到标准输出。

依次执行输入的语句:如果语句为输出语句,则相应输出一行变量的值的长度除以 1000000007 的余数。

样例1输入

 

6
1 a hello
1 b world
2 c $a $b
3 c
1 a hi
3 c

样例1输出

10
7

样例1解释

本样例即为题目描述中的例子。

样例2输入

5
1 var value
3 var
3 val
1 var $var $val $var
3 var

样例2输出

5
0
10

样例2解释

执行第一条语句后,变量 var 的值为 value,因此第二条语句输出 5;执行第三条语句时,变量 val 并未被赋值,因此其值为初始的空字符串,输出 0;执行第四条语句后,变量 var 的值为 valuevalue,因此第五条语句输出 10

 

子任务

测试点nn语句类型表达式的性质
1, 2≤200≤200无间接赋值语句每个表达式仅有1个字符串操作数
3, 4每个表达式仅有1个操作数
5, 6每个表达式包含不超过100个操作数
7, 8包含所有类型语句
9, 10≤2000≤2000

全部的数据满足:变量的总数不超过 1000 个,且每个变量的名称、字符串的长度不超过 50 个字符。

 解答

 题目描述很长,是一道字符串题,难度方面,我觉得要是把stringstream和map结合起来用就是一道中等难度或者送分题,废话不多说,直接开整:

题目大意:

输入n行字符串作为表达式,且表达式第一个字符代表着操作类型

第一个字符为1:直接赋值表达式

格式:1 + 变量名 + 一些操作数(空格分开)

如样例2:1  var  $var $val $var  就是var赋值三个操作数,分别是$var,$val,$var

其中$符号代表该操作数是一个变量,需要根据变量名(不含$)找到它的存的字符串

如果该变量不存在,则缺省为空字符串

第一个字符为2:动态赋值表达式

如样例1中:2 c $a $b

这里c是赋值为$a $b,可知是变量a和变量b储存的字符串相加,但是不能直接把a和b储存的字符串赋值给c,因为c是动态赋值,c需要随着a和b的改变而改变,所以我们想到把c赋值为$a $b,等到需要用c的时候再用一个函数读取变量a和变量b。

第一个字符串为3:输出表达式

5
1 var value
3 var
3 val
1 var $var $val $var
3 var

输出表达式格式:3 + 变量名

根据变量名输出该变量储存的字符串长度

如样例2:

先把value赋值给var

输出变量var字符串长度为5

然后输出变量val长度,因为val不存在,故缺省为空字符串,输出0

把var赋值为$var $val $var,也就是valuevalue,输出10

思路大致就是这样,解决这个问题用 stringstream 很合适,很舒服,因为这题的输入有大量包含空格的字符串,而stringstream可以按照空格分隔读取字符串

1. stringstream 是什么?

stringstream 是 C++ 中 <sstream> 头文件提供的类,用于在字符串中进行类似 cin/cout 的格式化输入输出操作。stringstream 常用于一次性解析一行中的多个字段。

2. 使用 stringstream 读取字符串的方法

方法一:使用 >> 按空格分割读取,这是最常用的方式,适用于将字符串按空格分词读入多个变量:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;int main() {string input = "hello world 123";stringstream ss(input);string word1, word2;int num;ss >> word1 >> word2 >> num;cout << "Word1: " << word1 << endl; // hellocout << "Word2: " << word2 << endl; // worldcout << "Num: " << num << endl;     // 123
}

方法二:使用 getline() 读取整行或指定分隔符的内容

如果你想以某个特定符号作为分隔符,比如逗号 , 或冒号 :,可以这样写:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;int main() {string input = "apple,banana,orange";stringstream ss(input);string token;while (getline(ss, token, ',')) {cout << token << endl;}
}

总结:stringstream 读取字符串方法对比

方法

用途

示例

ss >> var

按空格/换行/Tab 分隔读取

ss >> a >> b;

getline(ss, str, delim)

按指定分隔符读取整段字符串

getline(ss, token, ',');

特点1:stringstream 可以控制读取变量的个数

它不会自动读取所有内容,而是根据你写多少次 >> 来决定读几个变量。所以你可以通过控制使用 >> 的次数来精确地控制从 stringstream 中读取多少个变量。

#include <iostream>
#include <sstream>
#include <string>int main() {std::string line = "apple banana cherry date";std::stringstream ss(line);std::string a, b, c;// 仅读取前两个变量if (ss >> a >> b) {std::cout << "a: " << a << "\n";  // 输出: applestd::cout << "b: " << b << "\n";  // 输出: banana}// 再读一个(第三个)if (ss >> c) {std::cout << "c: " << c << "\n";  // 输出: cherry}// 剩下的部分可以继续读,也可以忽略
}

在这个例子中:

  • 我们只读了三个变量 (a, b, c),即使字符串中有四个单词;
  • 第四个单词 "date" 没有被读取。

 控制方式总结

方法

说明

ss >> a >> b;

明确读取两个变量

使用if (ss >> var)判断是否成功读取

避免越界或格式错误

结合while (ss >> word)

可以循环读取全部变量

如果你想读取不确定数量的变量

比如一行中有多个空格分隔的单词,你可以用循环:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>int main() {std::string line = "one two three four five";std::stringstream ss(line);std::vector<std::string> words;std::string word;while (ss >> word) {words.push_back(word);}std::cout << "Total words: " << words.size() << "\n";for (const auto& w : words)std::cout << w << "\n";
}
  • >> 会跳过空白字符(空格、换行、Tab);
  • 如果你希望保留空格,应该使用 getline()
  • 如果输入格式不一致,建议加判断防止程序崩溃;
  • 多余的数据不会报错,只是留在流里未被读取;

 

特点二:接着读

stringstream 在读取时会维护一个内部的位置指针(读指针) ,如果你没有一次性把内容全部读完,那么下一次读取的时候,它会从上次结束的位置继续读取


🧠 类比理解

你可以把 stringstream 想象成一个“文件流”或者“输入流”,就像你读一个文件一样,有一个“当前读到哪了”的概念。

#include <iostream>
#include <sstream>
#include <string>int main() {std::string line = "apple banana cherry date";std::stringstream ss(line);std::string a, b;// 第一次读两个单词ss >> a >> b;std::cout << "First read: " << a << " " << b << "\n";  // apple bananastd::string c, d;// 再次读两个单词ss >> c >> d;std::cout << "Second read: " << c << " " << d << "\n";  // cherry date
}

输出 

First read: apple banana
Second read: cherry date

补充知识点:如何重置位置指针?

如果你想让 stringstream 重新从开头读一遍 ,可以使用 .seekg() 方法:

std::stringstream ss("hello world");std::string s1, s2;
ss >> s1 >> s2;  // s1=hello, s2=worldss.seekg(0);     // 回到开头std::string s3, s4;
ss >> s3 >> s4;  // s3=hello, s4=world
  • stringstream 的读写行为和 cin 类似,不是像字符串那样可以反复访问;

总结

问题

回答

stringstream是否记住上一次读到哪里?

✅ 是的,它维护了一个读指针

没读完再次读取会不会从头开始?

❌ 不会,会接着上次的位置继续读

如何让它从头读?

使用ss.seekg(0)

如何清空整个 stringstream?

可以用

ss.str(""); ss.clear();

进阶(可跳过,不用这个用substr截取字符串也行)

如果你想获取 还未被读取的部分字符串 ,可以用下面这种方法: 

#include <iostream>
#include <sstream>
#include <string>int main() {std::stringstream ss("hello world this is a test");std::string a, b;ss >> a >> b;  // 已经读了 "hello" 和 "world"// 获取剩余部分std::string rest;std::getline(ss, rest);  // 从当前指针位置读到结尾std::cout << "Remaining string: " << rest << std::endl;// 输出: " this is a test"
}

std::getline(ss, rest); 会从当前位置开始读到结尾,并且自动跳过前面的空白字符 (如空格、Tab)。如果你不希望它跳过空白,可以这样写:

std::string rest(std::istreambuf_iterator<char>(ss),std::istreambuf_iterator<char>());

 

map<string, string> mp 的作用详解

✅ 它是一个存储变量名和对应值的容器

map<string, string> mp;

 map<key,value>mp

  • mp 用于保存用户定义的所有变量名及其对应的字符串值。
  • 键(key)是变量名(string 类型)
  • 值(value)是变量的内容(string 类型)

 本题变量名是字符串,储存的值也是字符串,用map建立变量名到储存的实际字符串的映射效果很好,可以用 mp[a] 直接访问变量a储存的字符串

总结:map<string, string> 的好处一览

优势

描述

✅ 自动排序(这里没用到)

键值有序,方便遍历和调试

✅ 支持默认访问

mp[key]用键可以直接访问值value

✅ 无哈希冲突

更加理论安全

✅ 小数据高效

对少量变量完全胜任

代码一览 

#include <bits/stdc++.h>
using namespace std;
map<string, string> mp;
string f(string s)
{if (s[0] == '$')s.erase(0, 1);elsereturn s;if (mp.find(s) != mp.end())return mp[s];elsereturn "!NOT  FOUND!";
}
int main()
{int n;cin >> n;cin.ignore();for (int i = 0; i < n; i++){string s;getline(cin, s);// 直接赋值变量if (s[0] == '1'){s.erase(0, 2);stringstream ss(s);string a, b, word;ss >> a;while (ss >> word){b += f(word);// cout << b << endl;}mp[a] = b;// cout << "1:" << a << " " << b << endl;}if (s[0] == '2'){s.erase(0, 2);stringstream ss(s);string a, b;ss >> a;getline(ss, b);b.erase(0, 1);mp[a] = b;// cout << "2:" << a << b << endl;}if (s[0] == '3'){s.erase(0, 2);if (mp.count(s)){stringstream ss(mp[s]);string ans, word;while (ss >> word){ans += f(word);}cout << ans.size() % 1000000007 << endl;// cout << ans << endl;}else{mp[s] = "";cout << 0 << endl;}}}
}

 优化:

使用unordered_map<string,string>不需要排序,节省时间 

 

 

 

 

 

 

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

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

相关文章

深度学习:智能车牌识别系统(python)

这是一个基于opencv的智能车牌识别系统,有GUI界面。程序能自动识别图片中的车牌号码,并支持中文和英文字符识别,支持选择本地图片文件,支持多种图片格式(jpg、jpeg、png、bmp、gif)。 下面,我将按模块功能对代码进行分段说明: 1. 导入模块部分 import tkinter as tk…

Missashe考研日记-day35

Missashe考研日记-day35 1 专业课408 学习时间&#xff1a;3h学习内容&#xff1a; 完结撒花&#xff01;&#xff01;今天把OS最后一节的内容学完了&#xff0c;操作系统也算是告一段落了&#xff0c;接下来是计网时间&#xff01;不过计网我是上学期才学过的&#xff0c;当…

【Bootstrap V4系列】学习入门教程之 组件-下拉菜单(Dropdowns)

Bootstrap V4系列 学习入门教程之 组件-下拉菜单&#xff08;Dropdowns&#xff09; 下拉菜单&#xff08;Dropdowns&#xff09;一、Overview 概述二、Accessibility 可访问性三、Examples3.1 Single button 单按钮3.2 Split button 分割按钮 四、Sizing 尺寸 下拉菜单&#x…

红外遥控与NEC编码协议详解

在我们日常生活中&#xff0c;电视遥控器、空调遥控器、风扇遥控器&#xff0c;几乎都离不开“红外遥控”这项技术。虽然我们每天都在用&#xff0c;但你知道里面是怎么通信的吗&#xff1f;本篇文章将带你了解红外遥控的工作原理&#xff0c;重点解析目前应用最广泛的红外编码…

深入剖析 I/O 复用之 select 机制

深入剖析 I/O 复用之 select 机制 在网络编程中&#xff0c;I/O 复用是一项关键技术&#xff0c;它允许程序同时监控多个文件描述符的状态变化&#xff0c;从而高效地处理多个 I/O 操作。select 作为 I/O 复用的经典实现方式&#xff0c;在众多网络应用中扮演着重要角色。本文…

【Linux系列】目录大小查看

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

《AI大模型应知应会100篇》第48篇:构建企业级大模型应用的架构设计

第48篇&#xff1a;构建企业级大模型应用的架构设计 摘要&#xff1a;本文将提供企业级大模型应用的端到端架构设计方案&#xff0c;从系统设计原则到技术栈选择&#xff0c;从高可用保障到安全合规&#xff0c;全面覆盖构建稳健、可扩展、安全的大模型应用所需的工程实践。适合…

人协同的自动化需求分析

多人协同的自动化需求分析是指通过技术工具和协作流程&#xff0c;让多个参与者&#xff08;如产品经理、开发人员、测试人员等&#xff09;在需求分析阶段高效协作&#xff0c;并借助自动化手段提升需求收集、整理、验证和管理的效率与质量。以下是其核心要点&#xff1a; 1. …

【战略合作】开封大学_阀门产业学院+智橙PLM

12月20日&#xff0c;在核电厂阀门系列团体标准启动会上&#xff0c;开封大学阀门产业学院与橙色云互联网设计有限公司达成战略合作。 以平台赋能行业&#xff0c;让阀门教育“有的放矢” 会议与会者包括&#xff1a; 开封大学副校长 李治 中国国际科技促进会标准化工作委员…

element-ui日期时间选择器禁止输入日期

需求解释&#xff1a;时间日期选择器&#xff0c;下方日期有禁止选择范围&#xff0c;所以上面的日期输入框要求禁止输入&#xff0c;但时间输入框可以输入&#xff0c;也就是下图效果&#xff0c;其中日历中的禁止选择可以通过【picker-options】这个属性实现&#xff0c;此属…

计算机网络:深入分析三层交换机硬件转发表生成过程

三层交换机的MAC地址转发表生成过程结合了二层交换和三层路由的特性,具体可分为以下步骤: 一、二层MAC地址表学习(基础转发层) 初始状态 交换机启动时,MAC地址表为空,处于学习阶段。 数据帧接收与源MAC学习 当主机A发送数据帧到主机B时,交换机会检查数据帧的源MAC地址。…

【开源解析】基于Python的智能文件备份工具开发实战:从定时备份到托盘监控

&#x1f4c1;【开源解析】基于Python的智能文件备份工具开发实战&#xff1a;从定时备份到托盘监控 &#x1f308; 个人主页&#xff1a;创客白泽 - CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f40d;《Python开源项目实战》 &#x1f4a1; 热爱不止于代码&#xff0…

Windows 环境变量完全指南:系统变量、用户变量与 PATH 详解

1. 什么是环境变量&#xff1f; 环境变量&#xff08;Environment Variables&#xff09;是 Windows 系统中用于存储配置信息的键值对&#xff0c;它们可以影响系统和应用程序的行为。例如&#xff1a; PATH&#xff1a;告诉系统在哪里查找可执行文件&#xff08;如 python、j…

详解RabbitMQ工作模式之工作队列模式

目录 工作队列模式 概念 特点 应用场景 工作原理 注意事项 代码案例 引入依赖 常量类 编写生产者代码 编写消费者1代码 编写消费者2代码 先运行生产者&#xff0c;后运行消费者 先运行消费者&#xff0c;后运行生产者 工作队列模式 概念 在工作队列模式中&#x…

数据结构-非线性结构-二叉树

概述 /** * 术语 * 根节点&#xff08;root node&#xff09;&#xff1a;位于二叉树顶层的节点&#xff0c;没有父节点。 * 叶节点&#xff08;leaf node&#xff09;&#xff1a;没有子节点的节点&#xff0c;其两个指针均指向 None 。 * 边&#xff08;edge&#xff09;&…

芯片笔记 - 手册参数注释

芯片手册参数注释 基础参数外围设备USB OTG&#xff08;On-The-Go&#xff09;以太网存储卡&#xff08;SD&#xff09;SDIO 3.0(Secure Digital Input/Output)GPIO&#xff08;General Purpose Input/Output 通用输入/输出接口&#xff09;ADC&#xff08;Analog to Digital C…

力扣94. 二叉树的中序遍历

94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#…

深度学习:AI为老年痴呆患者点亮希望之光

引言 随着全球人口老龄化进程的加速&#xff0c;老年痴呆症已成为严重威胁老年人健康和生活质量的公共卫生问题。据世界卫生组织统计&#xff0c;全球每 3 秒钟就有 1 人被诊断为痴呆&#xff0c;预计到 2050 年&#xff0c;全球痴呆患者人数将从目前的约 5000 万激增至 1.52 亿…

抛物线法(二次插值法)

抛物线法简介 抛物线法&#xff08;Quadratic Interpolation Method&#xff09;是一种用于一维单峰函数极值搜索的经典优化方法。该方法通过在区间内选取三个不同的点&#xff0c;拟合一条二次抛物线&#xff0c;并求取这条抛物线的极值点作为新的迭代点&#xff0c;从而逐步…

FreeRTOS如何检测内存泄漏

在嵌入式系统中&#xff0c;内存资源通常非常有限&#xff0c;内存泄漏可能导致系统性能下降甚至崩溃。内存泄漏是指程序分配的内存未被正确释放&#xff0c;逐渐耗尽可用内存。 FreeRTOS作为一种轻量级实时操作系统&#xff08;RTOS&#xff09;&#xff0c;广泛应用于资源受限…