OpenJudge NOI实战:如何用C++优雅处理字符串中的连续空格问题

从OpenJudge到NOI:C++字符串空格过滤的深度优化与实战心法

在信息学奥赛的赛场上,字符串处理是绕不开的基础课题。无论是OpenJudge上的日常练习,还是NOI(全国青少年信息学奥林匹克竞赛)的正式赛场,一道看似简单的“过滤多余空格”题目,往往能拉开选手之间的差距。这不仅仅是关于写出一个能通过测试的程序,更是关于如何在有限的内存和时间内,写出优雅、高效、鲁棒的代码。很多初学者会满足于一种解法,但真正的竞赛选手会像打磨艺术品一样,从多个维度审视同一个问题:字符数组与std::string的性能博弈、原地修改与新建字符串的空间取舍、以及面对不确定输入时的稳健处理策略。今天,我们就深入这个“小”问题,拆解其背后的大世界,分享一套从基础实现到竞赛级优化的完整心法。

1. 问题本质与竞赛场景分析

在OpenJudge NOI 1.7-23这类题目中,“过滤多余空格”的核心要求是:将输入字符串中连续的多个空格压缩为单个空格,同时保留单词之间最初的那个空格,并确保字符串首尾没有多余空格(通常题目隐含此要求)。这听起来简单,但在竞赛的高压环境下,我们需要快速、准确地洞悉其背后的几个关键点:

  • 输入边界的不确定性:题目可能给出单行字符串(用getline读取),也可能输入是多行、不定数量的单词流(需要while(cin >> str)循环读取)。前者考验对字符串的精细遍历,后者则考验对输入流终止条件(EOF)的理解和操作。
  • 性能的隐性要求:虽然一道题目的测试数据可能不大,但养成关注性能的习惯至关重要。在更复杂的赛题中,字符串处理可能只是其中一环,低效的实现会成为整个算法的瓶颈。我们需要思考:是使用C风格字符数组进行底层操作更快,还是利用std::string的便利性更划算?内存拷贝的次数是否可以减少?
  • 代码的简洁性与可读性:在分秒必争的比赛中,代码不仅要快,还要写得快,且不易出错。一个逻辑清晰、行数简洁的解法,能为你节省宝贵的调试时间。

我们先来看一个最直观,但也最值得深究的解法:遍历并构造新字符串。

2. 基础解法剖析:遍历与构造的艺术

这种思路是创建一个新的字符串(或字符数组),遍历原字符串,根据空格连续出现的规则,选择性地将字符追加到新字符串中。

2.1 使用字符数组(C风格字符串)

#include <cstdio>
#include <cstring>

int main() {
    char input[1005];
    char output[1005];
    fgets(input, 1005, stdin); // 使用fgets安全读取,包含可能的换行符

    int input_len = strlen(input);
    int output_idx = 0;
    int space_count = 0;

    for (int i = 0; i < input_len; ++i) {
        if (input[i] == ' ' || input[i] == '\n') { // 同时处理空格和结尾换行
            space_count++;
            if (space_count == 1) {
                output[output_idx++] = ' '; // 只保留第一个空格
            }
        } else {
            output[output_idx++] = input[i];
            space_count = 0; // 遇到非空格字符,重置空格计数器
        }
    }
    // 处理末尾可能被添加的空格
    if (output_idx > 0 && output[output_idx - 1] == ' ') {
        output_idx--;
    }
    output[output_idx] = '\0'; // 别忘了C风格字符串的结束符!

    printf("%s\n", output);
    return 0;
}

注意:使用字符数组时,必须手动管理内存和结束符 \0fgets 会读入换行符,所以在判断时需要考虑。同时,循环结束后检查并移除末尾可能多余的空

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值