二进制加法 | 豆包MarsCode AI刷题

81 阅读5分钟

今天讲一个标注难度是难,实际上还挺好写的一个题目,模拟二进制加法

题目分析

我们面临的任务是将两个二进制字符串相加,并输出其对应的十进制和。输入的二进制字符串可能非常长,因此需要设计一个高效的算法。

  • 输入:两个二进制字符串 binary1binary2,可能具有不同的长度。
  • 输出:这两个二进制字符串的和,以十进制的形式表示。

二进制加法的基础

二进制加法与十进制加法类似,但由于只有两个数(0 和 1),规则更为简单:

  1. 0 + 0 = 0
  2. 1 + 0 = 10 + 1 = 1
  3. 1 + 1 = 10,即进位。

因此,二进制加法的步骤大致如下:

  1. 从二进制数的最低位开始相加。
  2. 如果两位的和为 2,产生进位,并将该位的结果设置为 0。
  3. 如果两位的和为 1,结果为 1,不产生进位。
  4. 如果没有更多的位可加但仍有进位,则在最终结果的最高位添加进位。

算法设计

为了解决这个问题,我们可以使用模拟二进制加法的方式,逐位相加。以下是我们的基本思路:

  1. 将两个二进制字符串从右向左反转,以便我们从最低位开始逐位加法
  2. 对齐两个二进制字符串,确保它们的长度相同,如果长度不等,则在较短的字符串末尾补充零
  3. 遍历每一位,模拟加法,并处理进位
  4. 将最终的结果累加并转为十进制数

代码实现

def solution(binary1, binary2):
    # 反转字符串并转换为列表
    Array1 = list(reversed(list(binary1)))
    Array2 = list(reversed(list(binary2)))

    # 补齐位数,确保两者长度一致
    len_diff = len(Array1) - len(Array2)
    if len_diff > 0:
        Array2.extend([0] * len_diff)  # 在较短的二进制串后面补零
    elif len_diff < 0:
        Array1.extend([0] * (-len_diff))  # 在较短的二进制串后面补零

    # 将字符转为数字
    Array1 = list(map(int, Array1))
    Array2 = list(map(int, Array2))

    ans = 0  # 用于存储结果
    adv = 0  # 进位值

    # 从低位到高位逐位计算
    for i in range(len(Array1)):
        a, b = cal(Array1[i], Array2[i], adv)
        ans += a * (2 ** i)  # 根据位的位置累加到结果中
        adv = b  # 更新进位

    # 最后处理进位
    ans += adv * (2 ** (i + 1) if i >= 0 else 0)

    return str(ans)

def cal(a, b, c):
    """ 计算每一位的加法以及进位  (三引号注释)"""
    res = [0, 0]  # res[0] 是该位的结果,res[1] 是进位
    if a + b + c == 1 or a + b + c == 3:
        res[0] = 1
    if a + b + c >= 2:
        res[1] = 1
    return res

if __name__ == "__main__":
    # 测试用例
    print(solution("101", "110") == "11")
    print(solution("111111", "10100") == "83")
    print(solution("111010101001001011", "100010101001") == "242420")
    print(solution("111010101001011", "10010101001") == "31220")

代码详解

  1. 反转和补齐:

    • 首先反转输入的二进制字符串 binary1binary2,这样便可以从最低位开始进行加法
    • 接着,如果两个二进制数的长度不相等,补零,让它们的长度一致。这一步是为了保证两数加法时不会丢失高位信息
  2. 模拟加法:

    • 使用 cal 函数来计算每一位的加法结果和进位。如果当前位的和为 1 或 3(即存在进位或本身是 1),则该位的结果为 1;如果和为 2,产生进位
    • 对于每一位,将结果乘以对应的权重(即 2^i)加到 ans 中,并更新进位 adv
  3. 进位处理:

    • 最后,我们需要检查是否有多余的进位,如果有,则将其加到最终结果中。

时间复杂度分析

  • 假设 n 是较长二进制字符串的长度。
  • 反转和补齐操作的时间复杂度是 O(n)。
  • 遍历二进制数并计算每一位的加法和进位,时间复杂度也是 O(n)。
  • 因此,该算法的整体时间复杂度为 O(n),这是一个线性时间复杂度的算法,满足题目要求。

测试用例

  1. solution("101", "110")
    输入的两个二进制字符串分别为 "101" 和 "110"。它们相加后为 "1011",对应的十进制数为 11。
  2. solution("111111", "10100")
    输入的二进制字符串分别为 "111111" 和 "10100"。相加后的结果为 "1010011",对应的十进制数为 83。
  3. solution("111010101001001011", "100010101001")
    输入的二进制字符串分别为 "111010101001001011" 和 "100010101001"。它们相加后为 "111010111101110110",对应的十进制数为 242420。
  4. solution("111010101001011", "10010101001")
    输入的二进制字符串分别为 "111010101001011" 和 "10010101001"。它们相加后为 "11111111111001001",对应的十进制数为 31220。

结论

今天介绍了如何实现一个时间复杂度O(n^2)以内的算法来处理二进制字符串的加法。通过逐位模拟二进制加法,并利用线索化的思想来处理进位,我们能够避免使用高精度整数运算,确保算法在处理非常长的二进制字符串时仍能保持线性时间复杂度 O(n)。这种方法不仅符合时间复杂度要求,还能适应不同长度的输入,具备较好的扩展性。