二进制加法

519 阅读1分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

前言

笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。

系列文章收录《算法》专栏中。

问题描述

给定两个 01 字符串 a 和 b ,请计算它们的和,并以二进制字符串的形式输出。

输入为 非空 字符串且只包含数字 1 和 0。

示例 1:

输入: a = "11", b = "10"
输出: "101"

示例 2:

输入: a = "1010", b = "1011"
输出: "10101"

提示:

  • 每个字符串仅由字符 '0' 或 '1' 组成。
  • 1 <= a.length, b.length <= 10^4
  • 字符串如果不是 "0" ,就都不含前导零。

确定学习目标

对《二进制加法》的算法过程进行剖析。

剖析

  1. 首先对二进制进行单纯的加法并不难,直接使用十进制去理解,无非是进位不一样,从逢十进一改成逢二进行。
  2. 拿到字符串进行从后开始取每一位进行相加,以长度较长字符串为基准,长度较短的缺少位按照0进行补位即可。
  3. 设每位相加的结果为a,进位(没有或者不足就是0)为b,每位相加的结果为c,每位进位为d。那么c=(a+b)%2;d=(a+b)/2。
  4. 最后判断进位是否大于0,是的话最高位补一位为1。
  5. 由于是从最后位开始的结果需要倒转。

此算法没有涉及到新的知识点,无非就是看你对事务本质的理解并使用代码去实现它,所以还算比较简单。

注意需要对字符串进行非空和只包含数字 1 和 0的判断和限制。

代码

/**
 * 1. 首先对二进制进行单纯的加法并不难,直接使用十进制去理解,无非是进位不一样,从逢十进一改成逢二进行。
 * 2. 拿到字符串进行从后开始取每一位进行相加,以长度较长字符串为基准,长度较短的缺少位按照0进行补位即可。
 * 3. 设每位相加的结果为a,进位(没有或者不足就是0)为b,每位相加的结果为c,每位进位为d。那么c=(a+b)%2;d=(a+b)/2。
 * 4. 最后判断进位是否大于0,是的话最高位补一位为1。
 * 5. 由于是从最后位开始的结果需要倒转。
 *
 * @param a
 * @param b
 * @return
 */
public static String addBinary2(String a, String b) {
    //进行非空判断
    if (isEmpty(a) || isEmpty(b)) {
        throw new RuntimeException("a或b存在为空");
    }
    int al = a.length();
    int bl = b.length();
    //对长度进行判断
    if (al > 10000 || bl > 10000) {
        throw new RuntimeException("a或b存在长度大于10000");
    }
    //取al和bl之间较大的,用于以长度较长字符串为基准来遍历
    int max = Math.max(al, bl);
    //进位默认位0
    int carry = 0;
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < max; i++) {
        if (i <= al - 1) {
            char aCharAt = a.charAt(i);
            //每个字符串仅由字符 '0' 或 '1' 组成
            if ((aCharAt != '0' && aCharAt != '1')) {
                throw new RuntimeException("a或b包含除0和1之外的字符");
            }
        }
        if (i <= bl - 1) {
            char bCharAt = b.charAt(i);
            //每个字符串仅由字符 '0' 或 '1' 组成
            if ((bCharAt != '0' && bCharAt != '1')) {
                throw new RuntimeException("a或b包含除0和1之外的字符");
            }
        }

        //从最后一位开始,位不足补0
        carry += i < al ? a.charAt(al - 1 - i) - '0' : 0;
        carry += i < bl ? b.charAt(bl - 1 - i) - '0' : 0;
        //每位相加的结果为c,c=(a+b)%2。这里需要字符所以需要+'0'对应的ascii码(为48)再强转为char
        result.append((char) (carry % 2 + '0'));
        //每位进位为d,d=(a+b)/2
        carry /= 2;
    }
    //最后判断进位是否大于0,是的话最高位补一位为1。
    if (carry > 0) {
        result.append('1');
    }
    //由于是从最后位开始的结果需要倒转。
    return result.reverse().toString();
}