二进制数之和| 豆包MarsCode AI 刷题

85 阅读4分钟

二进制之和

题目

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

测试样例

样例1:

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

样例2:

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

思路

为了解决这个问题,我们需要了解二进制加法是如何进行的。

二进制数的加法与十进制数的加法类似,但操作基于二进制数的规则,即只有0和1两个数字,并且遵循“逢二进一”的原则。具体步骤如下:

  1. 对齐位数:将两个二进制数对齐,使它们的最低有效位(最右边的位)对齐。如果两个数的位数不同,可以在较短数的前面补0,使其位数相同。
  2. 逐位相加:从最低有效位开始,逐位相加。
    • 如果两个位上的数字之和为0或1,则结果直接为该数字。
    • 如果两个位上的数字之和为2,则写0并向前一位进1(即“逢二进一”)。
  3. 处理进位:将每一位的进位加到下一位的和中,继续逐位相加,直到处理完所有位和所有进位。
  4. 写结果:将所有位的和(包括可能的最高位进位)写在一起,得到最终的和。

对于这道题,当然我们需要将字符串反转才能做到上述步骤的第一步(对齐位数);并且我们还需要一个数标明进位数,随后就开始遍历这两个二进制字符串,进行逐位相加(即:目标字符串的每一位为两个字符串对应位置的数字相加再加上进制数再模2的结果),直到某个字符串结束;最后处理较长字符串剩下部分和进制数相加的结果,并将之拼接到目标字符串上。(在这里,为了方便计算,直接把较短的字符串高位补零,使得两个字符串一样长)

具体实现

1、变量的定义以及初始化:

int carry = 0;
int result = 0;
StringBuilder target = new StringBuilder();
StringBuilder sb1 = new StringBuilder(binary1);
StringBuilder sb2 = new StringBuilder(binary2);
  • carry:用于存储进位,初始值为0。
  • result:用于存储最终的十进制结果,初始值为0。
  • target:一个 StringBuilder 对象,用于构建二进制和的结果。
  • sb1 和 sb2:分别将 binary1 和 binary2 转换为 StringBuilder 对象,以便于操作。

2、对两个字符串进行处理,使其长度相同,最后将其反转,方便后续计算

int length = binary1.length()>binary2.length()?binary1.length():binary2.length();
if(binary1.length()>binary2.length()){
    StringBuilder replacement = new StringBuilder();
    for (int i = 0; i < binary1.length() - binary2.length(); i++) {
        replacement.append('0');
    }
    sb2.insert(0, replacement.toString());
}else if(binary1.length()<binary2.length()){
    StringBuilder replacement = new StringBuilder();
    for (int i = 0; i < binary2.length() - binary1.length(); i++) {
        replacement.append('0');
    }
    sb1.insert(0, replacement.toString());
}
sb1.reverse();
sb2.reverse();
  • 通过比较 binary1 和 binary2 的长度,将较短的字符串前面补0,使两者长度相等。
  • 将 sb1 和 sb2 反转,以便于从最低有效位开始相加。

3、逐位相加

for(int i=0;i<length;i++){
    int res1 = (sb1.charAt(i)=='0')?0:1;
    int res2 = (sb2.charAt(i)=='0')?0:1;
    int value = res1+res2+carry;
    if(value>=2) {
        value%=2;
        carry=1;
    }else{
        carry=0;
    }
    char ch = (value == 0) ? '0' : '1';
    target.append(ch);
}
if(carry==1)target.append('1');
  • 遍历每一位,将对应的字符转换为0或1,并加上前一位的进位 carry
  • 如果和 value 大于等于2,则取模2得到当前位的值,并将进位 carry 设置为1;否则,carry 为0。
  • 将当前位的值添加到 target 中。
  • 如果循环结束后仍有进位 carry,则将其添加到 target 的末尾。

4、转换为十进制数,返回字符串

for(int i=0;i<target.length();i++){
    int res = (target.charAt(i)=='0')?0:1;
    result += res*(int) Math.pow(2.0,i);
}
return String.valueOf(result);
  • 遍历 target 中的每一位,根据其在二进制数中的位置(从最低有效位开始),计算其十进制值并累加到 result 中。
  • 注意:这里使用了 Math.pow(2.0, i) 来计算2的i次方,但由于 result 是整型,所以 Math.pow 的结果需要强制转换为 int 类型。然而,这种转换可能会导致精度损失,但在这个特定的场景下(计算二进制数的十进制值),由于结果总是整数,所以这种转换是安全的。
  • 返回 result 的字符串形式