67. 二进制求和 - 力扣(LeetCode)
文章更新:2021年10月23日15:14:06
问题描述及示例
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “1”
输出: “100”
示例 2:
输入: a = “1010”, b = “1011”
输出: “10101”
提示:
每个字符串仅由字符 ‘0’ 或 ‘1’ 组成。
1 <= a.length, b.length <= 104
字符串如果不是 “0” ,就都不含前导零。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-binary
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的题解
我的题解1(JavaScript原生API)
先将 a
和 b
由二进制字符串转换为十进制数字,然后再将求和结果通过 toString()
方法以指定的进制输出为字符串。(没错,就是这么巧妙~[doge])
API选手自信地写下了他的答案,结果马上遭受了一顿毒打:
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var addBinary = function(a, b) {
return (parseInt(a,2) + parseInt(b,2)).toString(2);
};
提交记录
执行结果:解答错误
通过测试用例:194 / 294
输入:
"10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101"
"110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011"
输出:
"110111101100010011000101110110100000011101000101011000000000000000000000000000000000000000000000000"
预期结果:
"110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000"
时间:2021/10/23 15:14
大意了……没办法,API选手只好另寻出路:
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var addBinary = function(a, b) {
return (BigInt(`0b${a}`) + BigInt(`0b${b}`)).toString(2);
};
提交记录
294 / 294 个通过测试用例
状态:通过
执行用时:80 ms, 在所有 JavaScript 提交中击败了50.84%的用户
内存消耗:38.9 MB, 在所有 JavaScript 提交中击败了95.94%的用户
时间:2021/10/23 15:26
这次总算是通过了~
有关 BigInt
的描述可以参看下方文档:
我的题解2(模拟竖式计算)
之前做过一道十进制的字符串相加的题目,可做参考:
参考:【算法-LeetCode】415. 字符串相加(数组;Array.map();解构赋值)_赖念安的博客-优快云博客
本题也可以采用这种方法。
更新:2021年10月24日10:52:36
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var addBinary = function(a, b) {
let shortNum, longNum;
[shortNum, longNum] = (a.length < b.length) ? [a, b] : [b, a];
let shortArr = shortNum.split('').map(Number);
let longArr = longNum.split('').map(Number);
for(let i = shortNum.length; i < longNum.length; i++) {
shortArr.unshift(0);
}
longArr.unshift(0);
for(let i = shortArr.length - 1; i >= 0; i--) {
longArr[i] = (shortArr[i] + longArr[i+1]) >= 2 ? longArr[i] + 1 : longArr[i];
longArr[i+1] = (shortArr[i] + longArr[i+1]) % 2;
}
if(longArr[0] === 0) {
longArr.shift();
}
return longArr.join('');
};
提交记录
294 / 294 个通过测试用例
状态:通过
执行用时:80 ms, 在所有 JavaScript 提交中击败了51.02%的用户
内存消耗:39.9 MB, 在所有 JavaScript 提交中击败了47.42%的用户
时间:2021/10/24 10:51
这种方法就可以满足基本各种情况了,碰到其他进制的字符串相加题目也可以应用。
我的题解3(位运算模拟加法)
根据计算机组成原理的知识,我们知道,可以通过位运算来模拟实现加法运算,事实上,计算机也正是通过这种方法来完成加法运算的,因为计算机里的数据都是二进制形式。
可以参考下面的博客来对这种方法先做了解:
参考:位运算实现加、减、乘、除运算 - 简书
参考:二进制实现加法 - 金神敏 - 博客园
参考:异或运算 XOR 教程 - 阮一峰的网络日志
也可以在下方的【官方题解】中参阅相关的题解描述。
这在理论上确实是可行的,但是可惜的是,在JavaScript中,对于整数数字的位数有一定限制,如果超过这个限制就无法正常表示了。虽然JavaScript可以通过数字字符串的开头两位自动判断数字的进制,但是当字符串太长时,后面的位运算还是无法得到正确的结果。
递归思路
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var addBinary = function(a, b) {
if(b[0] === '0') {
return a;
}
a = '0b' + a;
b = '0b' + b;
let sum = (a ^ b).toString(2);
let carry = ((a & b) << 1).toString(2);
return addBinary(sum, carry);
};
没办法,还是没法儿逃过 BigInt
。
迭代思路
当然这里用递归思路也可以,但是 BigInt
还是得用上。
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var addBinary = function(a, b) {
a = BigInt(`0b${a}`);
b = BigInt(`0b${b}`);
let sum = a;
let carry = b;
while(b) {
sum = a ^ b;
carry = (a & b) << BigInt(1);
[a, b] = [sum, carry];
}
return sum.toString(2);
};
提交记录
294 / 294 个通过测试用例
状态:通过
执行用时:76 ms, 在所有 JavaScript 提交中击败了70.48%的用户
内存消耗:39.3 MB, 在所有 JavaScript 提交中击败了88.56%的用户
时间:2021/10/24 13:06
不过这就显得有点鸡肋的,都已经把字符串化成了数字了,直接相加不就得了吗?😂
官方题解
更新:2021年7月29日18:43:21
因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。
更新:2021年10月23日16:27:28
【更新结束】
有关参考
更新:2021年10月23日15:38:02
参考:BigInt - JavaScript | MDN
更新:2021年10月23日15:45:05
参考:【算法-LeetCode】415. 字符串相加(数组;Array.map();解构赋值)_赖念安的博客-优快云博客
更新:2021年10月24日11:07:01
参考:位运算实现加、减、乘、除运算 - 简书
参考:二进制实现加法 - 金神敏 - 博客园
参考:异或运算 XOR 教程 - 阮一峰的网络日志
更新:2021年10月24日13:08:36
参考:表达式和运算符 - JavaScript | MDN