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

30 阅读4分钟

问题描述

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

这道题如果用python来写这道题,那简直不要太简单,因为python它自带高精度啊TT 所以我交的时候用的也是python

def solution(binary1, binary2):
    decimal1 = int(binary1, 2)
    decimal2 = int(binary2, 2)
    
    result = decimal1 + decimal2
    return str(result)

if __name__ == "__main__":

但我是C++选手,所以当然要用C++实现!

那么这道题就用高精度来实现 众所周知,C++目前支持最大的整型是int128,只能支持21282^128级别的运算,而想要更大就只能手动高精度。

同样的高精度里面有不少技巧可以提升速度,当然对于这道题来说仅仅只是锦上添花,时间限制给O(n2)O(n^2)给的实在是太多了。 但是为了凑字数我还是介绍一些。

压位高精度。 高精度的实现本质上是在模拟竖式加减乘除法(但是除法有效率更高的写法) 人在计算的时候都是一位一位算的,但是计算机可以计算多位,所以我们不妨让一个单元保存的数大一些,即一位不再是0-9而可以是0-9999。通过压位我们等效于减少了位数,那么通常我们可以得到一个常数非常小的算法。而实际上正是这些常数使得压位高精度在数据范围比较大的时候表现十分优秀。

对于除法,我们当然可以像手算一样,模拟每一位该填什么,但是这样子我们会有10的常数,在压位的情况下常数更是大的吓人,因此这不是一个很好的办法。

那我们可以借助进制转化的思想,使用倍增! 首先以log*n的时间找到最大的,紧接着依次递减即可,总复杂度来到了n^2logn当然这题不要求哈。若是压位的话那么这个logn完全是可以被压掉的(bushi

当然以上的优化我都没写23333333 懒死了,只想着赶紧写完下班

下面是封装好的C++代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

template <class T>
inline void read(T &x)
{
    int fg = 1; char ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar()) fg = ch == '-' ? -1 : 1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + (ch ^ '0'); x *= fg;
}

const int N = 2e2 + 5;

struct math 
{ 
    int a[N],num = 0; 
    math operator = (int x)
    {
      num = 0;
      for(;x;x /= 10) a[++num] = x % 10;
    }
    math operator = (math x)
    {
        num = x.num;
        for(int i = 1;i <= x.num; ++ i) a[i] = x.a[i];
    }
    math operator * (int x)
    {
        math c; c.num = num + 1;
        memset(c.a,0,sizeof(c.a));
        for(int i = 1;i <= num; ++ i)
            c.a[i] += a[i] * x, c.a[i + 1] += c.a[i] / 10, c.a[i] %= 10;
        for(;!c.a[c.num]; -- c.num);
        return c;
    }
    math operator + (math b)
    {
        math c; c.num = max(num,b.num + 1);
        memset(c.a,0,sizeof(c.a));
        for(int i = 1;i <= c.num; ++ i)
            c.a[i] += a[i] + b.a[i], c.a[i + 1] += c.a[i] / 10, c.a[i] %= 10;
        for(;!c.a[c.num]; -- c.num);
        return c; 
    }
} s[N >> 1],ans;

int a[N],b[N],a1,b1,c[N],c1;

int main()
{
    freopen("P08.in","r",stdin); 
    freopen("P08.out","w",stdout);

    s[1] = 1;
    for(int i = 2;i <= 100; ++ i)
        s[i] = s[i - 1] * 2;

    char ch = getchar();
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) a[++a1] = ch - '0';

    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) b[++b1] = ch - '0';

    for(int i = 1;i <= a1; ++ i)
        c[a1 - i + 1] = a[i];
    for(int i = 1;i <= a1; ++ i) a[i] = c[i];
    for(int i = 1;i <= b1; ++ i)
        c[b1 - i + 1] = b[i];
    for(int i = 1;i <= b1; ++ i) b[i] = c[i];

    memset(c,0,sizeof(c)), c1 = max(a1,b1) + 1;
    for(int i = 1;i <= c1; ++ i)
        c[i] += a[i] + b[i], c[i + 1] += c[i] / 2, c[i] %= 2;
    for(;!c[c1]; -- c1);

    for(int i = 1;i <= c1; ++ i)
        if(c[i]) ans = ans + s[i];
    for(int i = ans.num;i; -- i)
        printf("%d",ans.a[i]);

    fclose(stdin); fclose(stdout);
    return 0;
}