[高精度]:55.二进制之和

73 阅读2分钟

问题描述

小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'


解题思路

  • 由于二进制数过长,直接转换肯定是不行的,我们通过模拟加法(高精度)得到求和后的字符串

    • 举个例子,模拟二进制加法 a=110,b=101a=110, b=101, 我们从低位开始模拟
    • 0+1+0(进位)=10 + 1 + 0(进位) = 1 ,进制为22,进位1/2=01 / 2 = 0, ans=1ans = 1
    • 1+0+0(进位)=11 + 0 + 0(进位) = 1 ,进制为22,进位1/2=01 / 2 = 0, ans=11ans = 11
    • 1+1+0(进位)=21 + 1 + 0(进位) = 2 ,进位为22,进位2/2=12 / 2 = 1, 剩2%2=0,ans=1102\%2 = 0,ans =110
    • 0+0+1(进位)=10 + 0 + 1(进位) = 1 ,进位为22,进位1/2=01 / 2 = 0, 剩1%2=1,ans=11011\%2 = 1,ans =1101
    • 由于ansans存储的是低位到高位,我们进行反转后就是答案 ans=1011ans = 1011
    • 如果想计算其他进制的求和,把/2%2/2和\%2换成相应进制即可
  • 二进制加法解决了,现在考虑如何把求和后的二进制数转为十进制

  • 常规的二进制转十进制计算方法为:

    • bn×2n+bn1×2n1++b1×21+b0×20b_n \times 2^n + b_{n-1} \times 2^{n-1} + \cdots + b_1 \times 2^1 + b_0 \times 2^0
    • 可以看出nn足够大时,我们无法计算出2n2^npypy请忽略)
    • 考虑将式子拆分,比如前两项bn×2n+bn1×2n1b_n \times 2^n + b_{n-1} \times 2^{n-1}
    • bn×2n=(bn×2)×2n1b_n \times 2^n = (b_n \times 2)\times2^{n-1}此时可以和第二项合并得
    • bn×2n+bn1×2n1=(bn×2+bn1)×2n1b_n \times 2^n + b_{n-1} \times 2^{n-1} = (b_n\times2 + b_{n-1})\times2^{n-1}
    • 我们把此时括号中的设为xx,来推导下一项
    • x×2n1+bn2×an2x\times 2^{n-1} + b_{n-2} \times a^{n-2}按照一样的方法可以得到
    • (2x+bn2)×2n2(2x + b_{n-2}) \times 2^{n-2}
    • 可以看出是一个逐渐相乘的过程,我们最后会计算到202^0
    • 括号中就是((((bn×2)+bn1)×2)+bn2)×2...((((b_n\times 2)+b_{n-1})\times 2)+b_{n-2})\times2 ...
    • ×2\times 2的操作我们可以换为高精度加法,就不会导致溢出问题了

核心代码

//高精度加法
string calc(string a, string b, int d) {
    string ans = "";
    int i = a.size() - 1; 
    int j = b.size() - 1;
    int carry = 0;
    while(i >= 0 || j >= 0 || carry > 0) {
        int s = 0;
        if(i >= 0) s += a[i] -'0', i--;
        if(j >= 0) s += b[j] -'0', j--;
        s += carry;
        carry = s / d;
        s = s % d;
        ans += to_string(s);
    }
    reverse(ans.begin(),ans.end());
    return ans;
}

std::string solution(std::string binary1, std::string binary2) {
    string s = calc(binary1, binary2, 2);
    string ans = "0";

    for(int i=0; i < s.length(); i++) {
        ans = calc(calc(ans, ans, 10),string(1,s[i]), 10);
    }
    return ans;

}