一道简单的算法题,题目描述如下:
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1 和 0。
示例 1:
输入: a = "11", b = "1"
输出: "100"
示例 2:
输入: a = "1010", b = "1011"
输出: "10101"
这道题用暴力法思路很简单,但是写起来很麻烦。二进制大家都知道如何计算,也知道如何进位,我们认为的来算感觉很简单,但是设计算法让计算机按照人类的思路(人类大脑计算二进制加法的方法类似于求解这道题的暴力法)来算的话,算法设计的很麻烦。废话不多说了,直接贴代码:
暴力法:
class Solution {
public:
string addBinary(string a, string b) {
int len1=a.size(),len2=b.size();
int carry=0;
string result;
//如果a和b之中任何一个为空,那么返回另一个
if(len1==0){
return b;
}
else if(len2==0){
return a;
}
//暴力法的循环,循环到某一个字符串的长度减为0为止
while(len1>0&&len2>0){
//相同位置上都是0的情况
if(a[len1-1]=='0'&&b[len2-1]=='0'){
//如果进位也是0,那么result左边添加一个0
if(carry==0){
result = '0'+result;
}
//如果进位不是0,那么结果加进位,然后进位置零
else if(carry==1){
result = '1'+result;
carry = 0;
}
}
//相同位置上都是1的情况
else if(a[len1-1]=='1'&&b[len2-1]=='1'){
if(carry==0){
result = '0'+result;
carry = 1;
}
else if(carry==1){
result = '1'+result;
}
}
//最后一种情况就是a和b相同位置上一个是1另一个是0
else{
if(carry==0){
result = '1'+result;
}
else if(carry==1){
result = '0' + result;
carry = 1;
}
}
len1--;
len2--;
}
/*接下来的两个判断语句,就是一个字符串比另一个字符串
长所产生的情况,按照人的想法是很好理解的,只要注意
进位问题就行了,这里就不详细解释了*/
if(len1>0){
if(carry==0){
while(len1>0){
result = a[len1-1] + result;
len1--;
}
}
else if(carry==1){
while(len1>0){
if(carry==0){
result = a[len1-1] + result;
}
else if(carry==1){
if(a[len1-1]=='0'){
carry = 0;
result = '1'+result;
}
else{
carry = 1;
result = '0'+result;
}
}
len1--;
}
}
}
if(len2>0){
if(carry==0){
while(len2>0){
result = b[len2-1] + result;
len2--;
}
}
else if(carry==1){
while(len2>0){
if(carry==0){
result = b[len2-1] + result;
}
else if(carry==1){
if(b[len2-1]=='0'){
carry = 0;
result = '1'+result;
}
else{
carry = 1;
result = '0'+result;
}
}
len2--;
}
}
}
/*最后这个if语句比较重要,判断两个字符串都加
完后进位是否为0,比较容易被人忽略*/
if(len1==0&&len2==0&&carry==1){
result = '1'+result;
}
return result;
}
};
上面的代码就是暴力法,大家也看的出来,这个算法无论是时间复杂性还是空间复杂性都很高,效率极低,但是有利于理解。
下面贴一个外国大佬(Sun Josan)的代码,只用了十行。
class Solution {
public:
string addBinary(string a, string b) {
string s;
s.reserve(a.size() + b.size());
int c = 0, i = a.size() - 1, j = b.size() - 1;
while(i >= 0 || j >= 0 || c == 1)
{
c += i >= 0 ? a[i--] - '0' : 0;
c += j >= 0 ? b[j--] - '0' : 0;
s.push_back((c & 1) + '0');
c >>= 1;
}
reverse(s.begin(), s.end());
return s;
}
};
字符串reserve函数的作用:reverse()会将区间[beg,end)内的元素全部逆序;
下面贴Python3的代码,Python3的代码用了递归,代码行数较少:
"""
递归,退出条件为a, b任意一个为空字符串。
加两数的末位决定是否进位。
末位加完,递归加前面的部分即可。
"""
class Solution:
def addBinary(self, a: str, b: str) -> str:
if a=='':
return b
if b=='':
return a
# 如果任意一个为0,则不需要进位,直接递归加前面的部分即可
if a[-1]=='0' or b[-1]=='0':
last = '0' if a[-1]==b[-1] else '1'
return self.addBinary(a[:-1],b[:-1]) + last
else:
# 末位均为1,需要进位
# 给a前面的部分添一位后再与b前面的部分递归加和
last = '0'
a = self.addBinary(a[:-1],'1')
return self.addBinary(a,b[:-1]) + last
如果有写的不合理的地方还望各位朋友批评指正。