华为OD机试 - 字符串压缩编码 - 线性扫描(Python/JS/C/C++ 新系统 100分)

在这里插入图片描述

华为OD机试 新系统 统一考试题库清单(持续收录中)以及考点说明(Python/JS/C/C++)

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

一、题目描述

给定一个只包含大小写英文字母的字符串,请实现字符串压缩编码功能。

压缩规则:

  • 如果字符连续出现次数大于 1,则用字符加上出现次数表示
  • 如果字符连续出现次数等于 1,则直接输出字符

二、输入描述

  • 输入一行,包含一个字符串 str(长度 1 ≤ |str| ≤ 1000)
  • 字符串只包含大小写英文字母

三、输出描述

输出压缩后的字符串

四、测试用例

测试用例1:

1、输入

aabcccccaaa

2、输出

a2bc5a3

3、说明

测试多个连续段,同时包含次数为 1 和大于 1 的情况

测试用例2:

1、输入

AAbB

2、输出

A2bB

3、说明

测试大小写敏感,b 和 B 是不同字符

五、解题思路

使用一次线性扫描。

维护一个变量 count,表示当前字符连续出现的次数。从字符串第二个字符开始:

当前字符与前一个字符相同:count++。

不相同:说明上一段连续字符结束,将“字符 + 次数”加入结果;如果次数为 1,只加入字符。

遍历结束后,最后一段字符还没有处理,需要额外加入结果。

Java 中使用 StringBuilder 保存压缩结果,因为字符串在构造过程中需要频繁追加,StringBuilder 比反复使用 String + String 更高效。

时间复杂度为 O(n),字符串只遍历一次;额外空间复杂度为 O(n),用于保存最终结果。

六、Python算法源码

s = input().strip()

# 使用列表保存压缩后的各个部分,
# 最后通过 join 一次性拼接成字符串
result = []

# 当前连续字符出现的次数
count = 1

# 从第二个字符开始扫描
for i in range(1, len(s)):

    if s[i] == s[i - 1]:
        # 当前字符和前一个字符相同,属于同一个连续段
        count += 1
    else:
        # 上一个连续字符段结束,先保存字符
        result.append(s[i - 1])

        # 出现次数大于 1 时才添加数字
        if count > 1:
            result.append(str(count))

        # 当前字符开始一个新的连续段
        count = 1

# 最后一段字符不会在循环中被处理,因此需要单独添加
result.append(s[-1])

if count > 1:
    result.append(str(count))

print(''.join(result))

七、JavaScript算法源码

const fs = require('fs');

// 从标准输入读取字符串
const s = fs.readFileSync(0, 'utf8').trim();

// 使用数组保存结果,最后 join 拼接,
// 避免循环过程中频繁创建新的字符串
const result = [];

let count = 1;

// 从第二个字符开始遍历
for (let i = 1; i < s.length; i++) {

    if (s[i] === s[i - 1]) {
        // 与前一个字符相同,连续次数增加
        count++;
    } else {
        // 上一个连续字符段已经结束
        result.push(s[i - 1]);

        // 次数大于 1 时才输出次数
        if (count > 1) {
            result.push(String(count));
        }

        // 当前字符开始新的连续段
        count = 1;
    }
}

// 补上最后一个连续字符段
result.push(s[s.length - 1]);

if (count > 1) {
    result.push(String(count));
}

console.log(result.join(''));

八、C算法源码

#include <stdio.h>
#include <string.h>

int main(void) {

    // 最大长度为 1000,多预留空间给字符串结束符 '\0'
    char str[1005];

    if (scanf("%1000s", str) != 1) {
        return 0;
    }

    int n = (int)strlen(str);

    // 当前连续字符出现次数
    int count = 1;

    /*
     * 从第二个字符开始扫描。
     * 当前字符和前一个字符相同则继续计数;
     * 不同则说明上一段连续字符已经结束,可以直接输出。
     */
    for (int i = 1; i < n; i++) {

        if (str[i] == str[i - 1]) {
            count++;
        } else {
            // 输出上一段字符
            putchar(str[i - 1]);

            // 连续次数大于 1 时才输出次数
            if (count > 1) {
                printf("%d", count);
            }

            // 当前字符开始新的连续段
            count = 1;
        }
    }

    /*
     * 最后一段字符不会在循环中被输出,
     * 因此遍历完成后进行补充处理。
     */
    putchar(str[n - 1]);

    if (count > 1) {
        printf("%d", count);
    }

    putchar('\n');

    return 0;
}

九、C++算法源码

#include <iostream>
#include <string>
using namespace std;

int main() {

    string str;
    cin >> str;

    // 保存最终压缩字符串
    string result;

    // 当前连续字符的出现次数
    int count = 1;

    /*
     * 线性扫描字符串。
     * 如果当前字符等于前一个字符,则继续累计次数;
     * 否则上一段连续字符结束,将其加入结果。
     */
    for (int i = 1; i < (int)str.size(); i++) {

        if (str[i] == str[i - 1]) {
            count++;
        } else {
            // 添加上一段对应的字符
            result += str[i - 1];

            // 连续次数超过 1 时,才需要添加次数
            if (count > 1) {
                result += to_string(count);
            }

            // 当前字符开始一个新的连续段
            count = 1;
        }
    }

    /*
     * 最后一段不会触发“字符发生变化”的条件,
     * 所以必须在循环结束以后单独处理。
     */
    result += str.back();

    if (count > 1) {
        result += to_string(count);
    }

    cout << result << '\n';

    return 0;
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 新系统 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值