Base32 的编码和解码问题(青训营X豆包MarsCode)|豆包MarsCode AI刷题

142 阅读8分钟

问题描述

你需要实现一个 Base32 的编码和解码函数。

相比于 Base32,你可能更熟悉 Base64,Base64 是非常常见的用字符串形式表示二进制数据的方式,在邮件附件、Web 中的图片中都有广泛的应用。

Base32 是 Base64 的变种,与 Base64 不同的地方在于 Base64 以 6 bit 为一组作为索引,而 Base32 以 5 bit 为一组作为索引,每一组用一个 ASCII 字符表示。Base 64 总共需要 64 个字符表示,而 Base32 则只需要 32 个字符表示。

Base32 的编码流程如下:

  • 对二进制数据进行预处理:如果二进制数据的 bit 数目不是 5 的倍数的话,在末尾补 0 直至为 5 的倍数。
  • 以 5 bit 为一组进行分组。
  • 将每一组的 5 bit 二进制转换为索引(0 - 31)。
  • 在索引 - 字符转换表中查询索引对应的字符。
  • 根据原始二进制数据的 bit 数目除以 40 后的余数,确定末尾需要补 + 的数目。
  • 如果原始二进制数据 bit 数目除以 40 后的余数是 0 的话,不需要补 +
  • 如果余数是 8,补 6 个 +
  • 如果余数是 16,补 4 个 +
  • 如果余数是 24,补 3 个 +
  • 如果余数是 32,补 1 个 +

Base32 的索引 - 字符转换表如下:

索引:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

字符:9 8 7 6 5 4 3 2 1 0 m n b v c x z a s d f g h j k l p o i u y t

你需要对字符串rawStr进行编码,并对encodedStr进行解码。

题目解析:理解问题,拆解思路

在学习编程和算法的过程中,解决实际问题是提升能力的关键。最近,我使用了豆包MarsCode AI平台的刷题功能,结合其智能化的辅助系统,不仅提升了我的编程能力,还加深了我对算法的理解。在此,我分享一些在使用该平台时的学习方法、心得和技巧,希望能为其他同学提供帮助。 在学习编程和算法的过程中,解决实际问题是提升能力的关键。最近,我使用了豆包MarsCode AI平台的刷题功能,结合其智能化的辅助系统,不仅提升了我的编程能力,还加深了我对算法的理解。在此,我分享一些在使用该平台时的学习方法、心得和技巧,希望能为其他同学提供帮助。

我选择了解析一个基础的算法题目:Base32 编码和解码。在这道题目中,我需要将一个字符串进行 Base32 编码,并且能对 Base32 编码进行解码。问题的核心是对编码和解码过程的理解,以及如何将字符串转化为二进制,再从二进制转回字符。

解析过程:

编码流程:首先,我将字符串转换为 ASCII 码,再转换为二进制字符串。接着,将二进制字符串按 5 位分组,对每组 5 位数字进行十进制转换,查找对应的字符,最终得到编码后的结果。 解码流程:解码时,我首先将 Base32 字符串转为二进制,然后按照每 8 位还原出原始字符。 我使用了豆包MarsCode AI平台的智能提示和代码示例,平台通过逐步解析题目,帮助我理解了编码和解码的具体步骤,同时给出了相应的代码框架。这不仅提升了我的编程能力,也帮助我更清楚地理解了二进制和编码方式的关系。

public class Main {
    static char[] index_table = "9876543210mnbvcxzasdfghjklpoiuyt".toCharArray();

    public static String solution(String rawStr, String encodedStr) {
        // Please write your code here
        String result1 = encode(rawStr);
        String result2 = decode(encodedStr);

        return String.format("%s:%s", result1, result2);
    }
    public static String encode(String rawStr) {
        char[] chars = rawStr.toCharArray();
        // StringBuilder ascii_encode = new StringBuilder();
        String buf;
        String raw_bin_encode = "";
        for (char c : chars) {
            buf = ((int) c) + "";
            raw_bin_encode = raw_bin_encode + dectobin(buf, 8);
        }
        String bin_encode = raw_bin_encode;
        while (bin_encode.length() % 5 != 0) {
            bin_encode = bin_encode.concat("0");
        }
        String encode = "";
        for (int i = 0; i < bin_encode.length() / 5; i++) {
            String dec = bintodec(bin_encode.substring(i * 5, i * 5 + 5));
            int index = Integer.parseInt(dec);
            encode = encode + index_table[index];
        }
        int res = raw_bin_encode.length() % 40;
        switch (res) {
            case 0:
                break;
            case 8:
                encode = encode + "++++++";
                break;
            case 16:
                encode = encode + "++++";
                break;
            case 24:
                encode = encode + "+++";
                break;
            case 32:
                encode = encode + "+";
                break;
            default:
                break;
        }
        return encode;
    }

    public static String decode(String encodedStr) {
        StringBuilder decoded = new StringBuilder();
        char[] encodedseg = encodedStr.toCharArray();
        int start = 0;
        for (int index = 1; index < encodedseg.length; index++) {
            if (encodedseg[index] != '+' && encodedseg[index - 1] == '+') {
                decoded.append(decodeSegment(String.valueOf(encodedseg).substring(start, index)));
                start = index;
            }
        }
        decoded.append(decodeSegment(String.valueOf(encodedseg).substring(start, encodedseg.length)));

        return decoded.toString();
    }

    public static String decodeSegment(String encodeStr) {
        char[] encodearry = encodeStr.toCharArray();
        String bin_encode = "";
        int count = 0;
        int dec = -1;
        for (char c : encodearry) {
            if (c == '+') {
                count = count + 1;
                continue;
            }
            for (int i = 0; i < index_table.length; i++) {
                if (index_table[i] == c) {
                    dec = i;
                    break;
                }
            }
            if (dec != -1) {
                bin_encode = bin_encode.concat(dectobin(dec + "", 5));
            }
        }
        int res = 0;
        switch (count) {
            case 0:
                break;
            case 6:
                res = 8;
                break;
            case 4:
                res = 16;
                break;
            case 3:
                res = 24;
                break;
            case 1:
                res = 32;
                break;
            default:
                break;
        }
        int length = ((int) bin_encode.length() / 40) * 40 + res;
        String raw_bin_encode = bin_encode.substring(0, length);
        String decode = "";
        for (int i = 0; i < length / 8; i++) {
            String dec8 = bintodec(raw_bin_encode.substring(i * 8, i * 8 + 8));
            decode = decode + (char) Integer.parseInt(dec8, 10);
        }
        return decode;
    }

    public static String dectobin(String decchar, int flag) {
        String bin = Long.toString(Long.parseLong(decchar, 10), 2);
        bin = String.format("%" + flag + "s", bin).replace(' ', '0');
        return bin;
    }

    public static String bintodec(String binchar) {
        String dec = Long.toString(Long.parseLong(binchar, 2), 10);
        return dec;
    }
}

知识总结:知识点的梳理与理解

在刷题的过程中,我总结出了一些新知识点,尤其是在二进制、编码转换和字符处理方面。以下是我在本次刷题过程中学到的一些要点:

编码与二进制的关系:编码的本质是将数据转换成特定的格式,Base32 编码使用了 5 位二进制进行转换,而 Base64 则使用 6 位二进制。这种差异让我更好地理解了编码方案的设计原理。 补充符号的应用:在 Base32 编码中,数据长度不满足时需要进行补充,这也是许多编码方式常见的操作。这让我更加熟悉了在处理编码问题时如何处理不足的部分。 算法的优化:在处理这类问题时,我学会了如何通过优化代码提高性能,特别是在处理较长字符串时,通过使用 StringBuilder 来替代传统的字符串拼接,有效避免了性能瓶颈。 对于其他入门同学,我建议在刷题时不仅要关注代码实现的细节,还要理解算法背后的原理,这样可以避免只会写代码的情况,帮助你更深入地理解编程的本质。

学习计划:如何制定高效的刷题计划

豆包MarsCode AI平台提供了智能算法题库,并且通过反馈错题,帮助我总结经验。结合该平台的特点,我总结了一套高效的学习方法:

制定阶段性目标:首先,我将学习任务分为多个小阶段。例如,我首先攻克字符串操作、编码转换类问题,然后逐步过渡到图算法、动态规划等复杂题目。每个阶段都设定合理的难度,逐步提高。

错题反馈与复习:通过平台提供的错题功能,我能方便地查看错误题目,分析原因,并进行针对性复习。我会定期回顾错题,理解自己在哪些方面做得不够好,进一步优化我的解题方法。

反思与总结:在每次做题后,我会记录自己遇到的难点和新的知识点,定期进行总结。每周抽出一些时间进行复习,确保掌握牢固。

工具运用:将 AI 刷题与其他学习资源结合

除了平台本身的刷题功能,我还结合了其他学习资源,例如在线教程、技术书籍和视频讲解。通过以下方式,我有效提高了学习效率:

配合理论学习:在刷题之前,我会先阅读相关的理论知识,理解算法的原理和常见的优化技巧。豆包MarsCode AI平台提供的详细题解和提示,帮助我将理论与实践相结合。

寻求社区帮助:平台的讨论区是一个宝贵的资源。当遇到难题时,我会查看其他用户的解答或者提问,与大家共同讨论,往往能得到不同的解题思路。

实践和复习相结合:通过反复练习和复习错题,我不仅能巩固自己的知识,还能在实践中提高自己的解题速度。

结语

通过使用豆包MarsCode AI刷题平台,我不仅提高了编程能力,还在反复刷题的过程中积累了丰富的算法知识。对我而言,刷题不仅仅是单纯的做题,而是一个不断学习和提升的过程。希望我的学习方法与心得能帮助大家更高效地使用该平台,同时也鼓励大家在学习过程中不断反思和总结,不断进步。