两个字符串相加——字符串进位的实践

一、二进制求和

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 题目

给定两个字符串形式的非负整数 num1num2 ,计算它们的和。

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/

https://leetcode-cn.com/problems/multiply-strings/solution/zi-fu-chuan-xiang-cheng-by-leetcode-solution/

 

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值