【二进制】【位运算】
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 为字符串 a
和 b
中的最大长度。
空间复杂度: O ( 1 ) O(1) O(1)。
// 反转字符串
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;
}
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 哦。