题解:55.二进制之和问题解析

157 阅读5分钟

学习笔记:二进制之和问题解析

题目描述

小U和小R喜欢探索二进制数字的奥秘。他们想找到一个方法,将两个二进制字符串相加并以十进制的形式呈现。这个过程需要注意的是,他们的二进制串可能非常长,所以常规的方法可能无法处理大数。小U和小R希望你帮助他们设计一个算法,该算法能在保证时间复杂度不超过 O(n^2) 的前提下,返回两个二进制字符串的十进制求和结果。

测试样例

样例1:

  • 输入:binary1 = "101", binary2 = "110"
  • 输出:'11'

样例2:

  • 输入:binary1 = "111111", binary2 = "10100"
  • 输出:'83'

样例3:

  • 输入:binary1 = "111010101001001011", binary2 = "100010101001"
  • 输出:'242420'

样例4:

  • 输入:binary1 = "111010101001011", binary2 = "10010101001"
  • 输出:'31220'

样例5:

  • 输入:binary1 = "11", binary2 = "1"
  • 输出:'4'

解题思路

1. 问题分析

  • 挑战:由于二进制字符串可能非常长,直接将其转换为整数(使用 int(binary, 2))可能会超出数据类型的范围,导致溢出或性能问题。
  • 目标:设计一个高效的算法,在时间复杂度不超过 O(n^2) 的前提下,计算两个长二进制字符串的和,并以十进制字符串形式返回结果。

2. 解决方案

  • 模拟二进制加法:从最低位(末尾)开始,逐位相加,处理进位,就像手工计算二进制加法一样。
  • 避免大数运算:通过字符操作和基本的整数计算,避免将整个字符串转换为大整数,提升算法的适用性和效率。
  • 结果转换:将得到的二进制结果转换为十进制字符串输出。

3. 算法步骤

  1. 初始化

    • 设定指针 ij,分别指向 binary1binary2 的末尾。
    • 初始化进位 carry 为 0。
    • 创建一个空列表 result 用于存储计算结果的二进制位。
  2. 逐位相加

    • ij 大于等于 0,或 carry 大于 0 时,执行以下操作:
      • 取当前位的数字 digit1digit2,如果指针小于 0,则视为 0。
      • 计算当前位的总和:total = digit1 + digit2 + carry
      • 计算当前位的结果:total % 2,将其加入 result
      • 更新进位:carry = total // 2
      • 指针 ij 向前移动一位(减 1)。
  3. 结果处理

    • 反转 result 列表,因为计算是从最低位开始的。
    • 将二进制结果列表转换为字符串。
    • 使用 int( , 2) 将二进制字符串转换为十进制整数。
    • 将整数转换为字符串,得到最终结果。

图解示例

以样例1为例:

  • 输入binary1 = "101", binary2 = "110"

  • 计算过程

    位索引digit1digit2carrytotalresult新的 carry
    21001[1]0
    10101[1,1]0
    01102[0,1,1]1
    -10011[1,0,1,1]0
  • 二进制结果1101(需要反转 result 列表)

  • 十进制结果11

代码详解

def solution(binary1, binary2):
    # 初始化变量
    i = len(binary1) - 1  # 指向 binary1 的末尾
    j = len(binary2) - 1  # 指向 binary2 的末尾
    carry = 0             # 进位
    result = []           # 存储二进制计算结果

    # 逐位相加
    while i >= 0 or j >= 0 or carry > 0:
        # 获取当前位的数字,如果索引小于 0,则视为 0
        digit1 = int(binary1[i]) if i >= 0 else 0
        digit2 = int(binary2[j]) if j >= 0 else 0

        # 计算当前位总和和进位
        total = digit1 + digit2 + carry
        result.append(total % 2)    # 当前位的结果(0 或 1)
        carry = total // 2          # 更新进位(0 或 1)

        # 指针前移
        i -= 1
        j -= 1

    # 反转结果以得到正确的顺序
    result.reverse()
    # 将二进制结果转换为字符串
    binary_str = ''.join(map(str, result))
    # 将二进制字符串转换为十进制整数,再转换为字符串输出
    decimal_result = str(int(binary_str, 2))

    return decimal_result

学习体会

1. 逐位计算的巧妙性

通过模拟手工加法,逐位计算避免了大数问题,非常实用。

2. 对进位的处理

理解进位在二进制加法中的作用,确保在每一步都正确处理进位。

3. 字符串和列表操作

熟练使用字符串索引、列表的 appendreverse 方法,提升编码效率。

对他人的建议

  • 理解算法原理:在编写代码前,先理清算法步骤,有助于代码的编写和调试。
  • 注意边界条件:处理字符串时,要考虑索引越界的情况,使用条件表达式避免错误。
  • 多练习类似问题:巩固对二进制运算和字符串处理的理解,提升编程能力。

总结

这道题目通过模拟二进制加法,要求我们处理可能非常长的二进制字符串的求和问题。在解决过程中,我们避免了大数运算,掌握了逐位计算的方法。这不仅提高了我们的算法设计能力,也增强了对基础编程概念的理解。