一、二进制求和
1.1 题目
给你两个二进制字符串,返回它们的和(用二进制表示)。输入为 非空 字符串且只包含数字 1
和 0
。
1.2、题解
我们可以借鉴「列竖式」的方法,末尾对齐,逐位相加。在十进制的计算中「逢十进一」,二进制中我们需要「逢二进一」。
1、先反转这个代表二进制数字的字符串,然后低下标对应低位,高下标对应高位。
2、我们使用一个变量 carry 表示上一个位置的进位,初始值为 0
3、记当前位置对其的两个位为 ai 和 bi,则每一位为 (carry+ai+bi) mod 2
4、下一位的进位为 (carry+ai+bi) / 2
5、最后如果 carry的最高位不为 0,则将最高位添加到计算结果的末尾。
1.3 代码
class Solution {
public:
string addBinary(string a, string b) {
string ans;
reverse(a.begin(), a.end()); // 翻转字符串a
reverse(b.begin(), b.end()); // 翻转字符串b
int n = max(a.size(), b.size()); // 求两个字符串的最大长度
int carry = 0; // 上一个位置的进位
for (size_t i = 0; i < n; ++i) {
carry += i < a.size() ? (a.at(i) == '1') : 0;
carry += i < b.size() ? (b.at(i) == '1') : 0; // 计算进位的值 carry+ai+bi
ans.push_back((carry % 2) ? '1' : '0'); // 当前位的值是carry mod 2
carry /= 2; // 进位的值是carry / 2
}
if (carry) {
ans.push_back('1');
}
reverse(ans.begin(), ans.end()); // 翻转
return ans;
}
};
当然你也可以直接把 a 和 b中短的那一个补 0 直到和长的那个一样长,然后从高位向低位遍历,对应位置的答案按照顺序存入答案字符串内,最终将答案串反转
class Solution {
public:
string addBinary(string a, string b) {
int carry = 0;
string res = "";
for (int i = a.size() - 1, j = b.size() - 1; i >= 0 || j >= 0; i--, j--)
{ // 从右往左遍历
int sum = carry;
sum += i >= 0 ? a[i] - '0' : 0; // 缺位就补0
sum += j >= 0 ? b[j] - '0' : 0; // 缺位就补0
res += (sum % 2) + '0'; // 获取res字符串
carry = sum / 2;
}
if (carry == 1) res += '1'; // 还有进位就加上
reverse(res.begin(), res.end()); // 最后翻转
return res;
}
};
其他方法,ASCIl码直接相加
class Solution {
public:
string addBinary(string a, string b) {
int lengthA = a.size();
int lengthB = b.size();
// 让两个字符串等长,若不等长,在短的字符串前补零,否则之后的操作会超出索引
while (lengthA < lengthB)
{
a = '0' + a;
++lengthA;
}
while (lengthA > lengthB)
{
b = '0' + b;
++lengthB;
}
for (int j = a.size() - 1; j > 0; --j) //从后到前遍历所有的位数,同位相加
{
a[j] = a[j] - '0' + b[j];
if (a[j] >= '2') //若大于等于字符‘2’,需要进一
{
a[j] = (a[j] - '0') % 2 + '0';
a[j - 1] = a[j - 1] + 1;
}
}
a[0] = a[0] - '0' + b[0]; //将ab的第0位相加
if (a[0] >= '2') //若大于等于2,需要进一
{
a[0] = (a[0] - '0') % 2 + '0';
a = '1' + a;
}
return a;
}
};
二、字符串相加
2.1 题目
给定两个字符串形式的非负整数 num1
和num2
,计算它们的和。
2.2 解析
1、我们定义两个指针 i 和 j 分别指向 num1和 num2 的末尾,即最低位;
2、同时定义一个变量 add 维护当前是否有进位,然后从末尾到开头逐位相加即可;
3、如果两个数字长度不同,这里我们统一在指针当前下标处于负数的时候返回 0,等价于对位数较短的数字进行了补零操作;
2.3 代码
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.length() - 1;
int j = num2.length() - 1;
int add = 0;
string ans = "";
while (i >= 0 || j >= 0 || add != 0) { // 从后往前,即从最低位遍历
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int result = x + y + add;
ans.push_back('0' + result % 10); // 获取当前位的值
add = result / 10; // 进位
i -= 1;
j -= 1;
}
// 计算完以后的答案需要翻转过来
reverse(ans.begin(), ans.end());
return ans;
}
};
其他方法,ASCii直接相加
class Solution {
public:
static constexpr int MaxNum = 7000;
string addStrings(string num1, string num2) {
int lenum1 = num1.length();
int lenum2 = num2.length();
char n[MaxNum + 1] = { 0 };
int index1 = lenum1 - 1;
int index2 = lenum2 - 1;
int index = max(index1, index2) + 1;
char bit = 0;
int num = 0;
while (index1 >= 0 && index2 >= 0)
{
num = num1[index1] + num2[index2] - '0' + bit;//0的ascill为48
if (num > 57)
{
n[index] = num - 10;
bit = 1;
}
else
{
n[index] = num;
bit = 0;
}
--index1;
--index2;
--index;
}
while (index1 >= 0)
{
num = num1[index1] + bit;
if (num > 57)
{
n[index] = num - 10;
bit = 1;
}
else
{
n[index] = num;
bit = 0;
}
--index1;
--index;
}
while (index2 >= 0)
{
num = num2[index2] + bit;
if (num > 57)
{
n[index] = num - 10;
bit = 1;
}
else
{
n[index] = num;
bit = 0;
}
--index2;
--index;
}
if (bit != 0)
{
n[index] = bit + '0';
}
char *p = n;
while ('\0' == *p)//去除多余的空白字符
p++;
return string(p);
}
};
三、两数相乘
3.1 题目
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
3.2 分析
本质上是道模拟题,模拟手算乘法的过程。想要做出这道题,需要知道一个数学定理:两个长度分别为 n 和 m 的数相乘,长度不会超过 n + m。因此我们可以创建一个长度为 n + m 的数组 res 存储结果。
3.3 代码
class Solution {
public:
string multiply(string num1, string num2) {
int n = num1.length(), m = num2.length();
// 使用数组代替字符串存储结果,则可以减少对字符串的操作
vector<int> res = vector<int>(m + n, 0);
for (int i = n - 1; i >= 0; i--) {
for (int j = m - 1; j >= 0; j--) {
int a = num1.at(i) - '0';
int b = num2.at(j) - '0';
int r = a * b;
r += res[i + j + 1];
res[i + j + 1] = r % 10; // 当前位
res[i + j] += r / 10; // 进位
}
}
string str;
for (int i = 0; i < n + m; i++) {
if (str.length() == 0 && res[i] == 0) continue;
str += (res[i] + '0'); // 将整数转换成字符
}
return str.length() == 0 ? "0" : str;
}
};
参考:
https://leetcode-cn.com/problems/add-binary/solution/er-jin-zhi-qiu-he-by-leetcode-solution/
https://leetcode-cn.com/problems/add-strings/solution/zi-fu-chuan-xiang-jia-by-leetcode-solution/