【面试经典150 | 位运算】二进制求和

Tag

【二进制】【位运算】


题目来源

67. 二进制求和


题目解读

以二进制字符串的形式返回两个二进制字符串的和。


解题思路

看到这个题目首先想到的方法可能是先把二进制字符转化成 int 型数字或者 long long 型数字,然后加和,最后将加和得到的结果再转化成二级制字符串。比如,将二进制字符串 "11" 转化成 3"10" 转化成 2,两个整数的和为 5,转会成二进制字符串为 101。该方法将我们不熟悉的二进制字符串加法转化成我们熟悉的整数的加法,对于部分数据的处理是没问题,但是处理较长的二进制字符串时,我们已知表示最大的整数类型的 long long(C/C++)都无法处理,会造成溢出的风险。

在 Python 和 Java 语言中,有一些可以表示更大数据的数据类型,该方法是可以实现,接下来主要是针对 C/C++ 语言中适用长度较大的字符串计算,接下来将要介绍的方法更具鲁棒性(Robust)。

方法一:模拟

平常我们接触的数多以十进制的形式存在,十进制的数之间的加法的计算规则是由低位到高位依次对齐,“逢十进一”。

在进行二进制数加法时可以参照十进制数的加法,由低位到高位依次对齐,不同于十进制的 “逢十进一”,二进制数加法是 “逢二进一”。

于是,计算二进制数加法时从最低位开始加,当两个数位之和等于 2 的时候就会产生进位,这个进位在下一位的两个数加和时要加上。进行对应位加法时,如果其中的一个字符已经遍历完毕,而另一个字符串还有二进制为没有遍历完,那么已经遍历完毕的二进制字符串要自动补零接着计算。按照这样的逻辑,于是有以下代码。

实现代码

class Solution {
public:
    string addBinary(string a, string b) {
        string ret;
        
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        
        int n = std::max(a.size(), b.size()), carry = 0;
        for(int i = 0; i < n; ++i){
            carry += (i < a.size()) ? (a.at(i) == '1') : 0;
            carry += (i < b.size()) ? (b.at(i) == '1') : 0;
            ret.push_back((carry % 2) ? '1' : '0');
            carry /= 2;
        }
        if(carry){
            ret.push_back('1');
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 为字符串 ab 中的最大长度。

空间复杂度: O ( 1 ) O(1) O(1)

其他语言

c

// 反转字符串
void reverse(char* s) {
    int n = strlen(s);
    for (int i = 0; i < n / 2; ++i) {
        char t = s[i];
        s[i]= s[n - 1 -i];
        s[n - 1 - i] = t;
    }
}

char* addBinary(char* a, char* b) {
    reverse(a);
    reverse(b);
    int len_a = strlen(a), len_b = strlen(b);
    
    int n = fmax(len_a, len_b);
    int carry = 0, idx = 0;
    char* res = (char*)malloc(sizeof(char) * (n+2));
    for (int i = 0; i < n; ++i) {
        carry += i < len_a ? (a[i] == '1') : 0;
        carry += i < len_b ? (b[i] == '1') : 0;
        res[idx++] = carry % 2 + '0';
        carry /= 2;
    }
    if (carry) {
        res[idx++] = '1';
    }
    res[idx] = '\0';
    reverse(res);
    return res;
}

写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_nn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值