当前位置:首页 > GESP > 洛谷B3870题:位操作与二进制转换解决变长编码

洛谷B3870题:位操作与二进制转换解决变长编码

3个月前 (08-28)

洛谷B3870题:位操作与二进制转换解决变长编码 洛谷题解 进制转换 位运算 C++ GESP GESP四级 第1张

一、题目解读

洛谷B3870题要求将给定的无符号长整型数转换为可变长度的字节编码,并输出其十六进制表示。题目核心在于设计一种高效的编码方案,需处理数字的二进制位分组、最高位标记及字节顺序反转等细节。该问题考察对二进制位操作的理解与算法逻辑的严谨性,尤其在边界条件(如0的特殊编码)与分组补位机制上的实现。

二、解题思路

1. 二进制转换与去前导0:自定义toBinaryString函数将数字转为二进制串,通过倒序取余法生成,并去除前导0(避免无效位)。

2. 分组与最高位标记:将二进制串按7位分组,不足位补0。通过makeByte函数生成字节,非最后一组设置最高位为1,区分数据段与结束标志。

3. 字节反转输出:因处理从低位开始,最终需反转字节顺序,确保正确解码顺序。

4. 边界处理:0的特殊情况单独编码为单字节0,避免空输出。

三、解题步骤

1. 输入数字N:通过cin获取用户输入的无符号长整型数。

2. 二进制转换:调用toBinaryString(N)生成二进制串,去除前导0。

3. 分组编码:

○ 从末尾开始,每次取最长7位子串(不足补0)。

○ 通过makeByte将子串转为字节,根据位置标记最高位。

○ 存入bytes容器,记录编码结果。

4. 字节反转:使用reverse函数反转字节顺序,确保高位在前。

5. 输出十六进制:循环遍历字节,按格式%02X输出,空格分隔。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 将数字转换为二进制字符串(去除前导0)
string toBinaryString(unsigned long long n) {
    if (n == 0) return "0"; // 0的特殊处理
    string binary;
    while (n > 0) {
        binary += (n % 2) + '0'; // 倒序取余生成二进制
        n /= 2;
    }
    reverse(binary.begin(), binary.end()); // 反转成正确顺序
    return binary;
}

// 将7位二进制字符串转换为字节(添加最高位)
char makeByte(const string& bits, bool isLast) {
    char byte = 0;
    for (int i = 0; i < 7; ++i) {
        char bit = (i < bits.size())? bits[i] - '0' : 0; // 不足位补0
        byte |= bit << (6 - i); // 按位左移拼接
    }
    if (!isLast) byte |= 1 << 7; // 非末尾组最高位设为1
    return byte;
}

// 主处理函数
vector<char> encodeNumber(unsigned long long n) {
    vector<char> bytes;
    if (n == 0) {
        bytes.push_back(0); // 0编码为单字节0
        return bytes;
    }
    
    string binary = toBinaryString(n);
    int len = binary.length();
    int pos = len;
    
    while (pos > 0) {
        int start = max(0, pos - 7); // 从末尾开始取7位组
        string group = binary.substr(start, pos - start);
        pos = start;
        
        // 补足7位
        while (group.length() < 7) {
            group = "0" + group;
        }
        
        bool isLast = (pos == 0);
        bytes.push_back(makeByte(group, isLast));
    }
    
    // 反转字节顺序(因处理从低位开始)
    reverse(bytes.begin(), bytes.end());
    return bytes;
}

int main() {
    unsigned long long N;
    cin >> N;
    
    vector<char> encoded = encodeNumber(N);
    
    // 输出十六进制表示
    for (size_t i =  encoded.size(); i >0; i--) {
        if (i!= encoded.size()) cout << " ";
        printf("%02X", (unsigned char)encoded[i-1]); // 强制类型转换避免警告
    }
    cout << endl;
    
    return 0;
}

五、总结

该解法通过模块化函数(二进制转换、字节生成、主逻辑)实现清晰编码流程,兼顾效率与边界处理。核心技巧在于:

● 二进制倒序生成避免额外反转操作;

● 分组补位与最高位标记简化解码逻辑;

● 字节反转确保大端序输出。

适用于需处理变长二进制数据的场景,算法简洁且易于扩展。未来可探索更紧凑的位运算优化,或结合动态规划优化分组效率。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣LCR182:字符串操作三连 从基础拼接到底层指针优化

力扣LCR182:字符串操作三连 从基础拼接到底层指针优化

题目重解需要将密码字符串从第target个字符开始进行重新排列,形成新的动态密码。例如输入"password"和target=3,结果应为"swordpas"。...

力扣540题:线性扫描法如何高效定位唯一数

力扣540题:线性扫描法如何高效定位唯一数

题目重解一个严格递增的有序数组中,除某个元素外,其余每个元素均出现两次。这个看似简单的条件背后隐藏着巧妙的规律——单一元素会打破数组的"成对对称性"。题目要求以O(log n)时间...

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

一、题目解读洛谷1184题要求处理一组地点列表与行程记录,统计其中匹配的天数。题目难点在于高效处理带有空格的字符串输入,以及快速判断每日行程是否在高手可去地点集合中。需要兼顾输入格式解析与算法效率。二...

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

一、题目解读洛谷1220题要求计算在n个位置放置灯的情况下,通过关闭连续区间灯并移动至区间端点,使得总耗电量最小。需考虑灯的功率与位置差异,设计高效的算法求解最优策略。二、解题思路1. 动态规划 +...

牛客NC67题解:汉诺塔递归算法与解题步骤

牛客NC67题解:汉诺塔递归算法与解题步骤

一、题目解读牛客NC67题要求解决汉诺塔问题,这是一个经典的递归算法题目。题目给定整数n,代表汉诺塔中的盘子数量,需要输出将n个盘子从起始柱移动到目标柱的所有步骤。汉诺塔问题规则为:每次只能移动一个盘...

手把手教你实现进制转换(C++代码注释+小白友好教程)

一、简介和特点进制转换是编程中常见的操作,即将数值从一种进制(如十进制)转换为另一种进制(如二进制、十六进制等)。本代码实现了一个通用的进制转换工具,具有以下特点:   ...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。