415. 字符串相加
题意:给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
返回值:返回相加后的结果字符串。
说明:
- 1、num1 和num2 的长度都小于 5100
- 2、num1 和num2 都只包含数字 0-9
- 3、num1 和num2 都不包含任何前导零
- 4、你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式
思路:
这道题主要考察对字符串的模拟,模拟两个整数相加的情况。
来看看我们做加法的情况。
步骤:
■ 1、从每个数从低位到高位依次相加,包括进位的数字。
■ 2、判断当前相加的数是否超过10,如果超过10往前进位,然后当前数减去10。
■ 3、循环步骤一和步骤二,直到把字符串遍历完。
■ 4、检查最后是否有进位,如果有进位,将进位加上,最后得到就是我们的结果。
提示:
■ 1、因为我们不确定最后结果的长度,所以我们常常将得到的每一位结果依次往结果字符串当中增加,这样得到的结果是反的,所以最后我们需要将结果字符串反转。
■ 2、我们处理每个字符串时,从最高位处理,最高位对应的是数字中的最低位。
C++ 代码
class Solution {
public:
string addStrings(string num1, string num2) {
string res; //存储结果字符串
int i=num1.size()-1,j=num2.size()-1,carry=0; //从最高位开始处理字符串
while(i>=0||j>=0){
if(i>=0) carry+=(num1[i]-'0');//分别检查每个字符串是否处理完
if(j>=0) carry+=(num2[j]-'0');
res.push_back((carry%10)+'0');//算得本位应该是多少
carry/=10; //算的是否进位
i--,j--;
}
if(carray)res.push_back(carray+'0');//检查最后是否还有进位
reverse(res.begin(),res.end()); //得到的结果是反的所以要将字符串反转,变成最终的结果
return res;
}
};
解决了这道题,可以去解决以下几道题:
高精度减法
题意:给定两个正整数,计算它们的差,计算结果可能为负数。
输入格式:共两行,每行包含一个整数。
输出格式:共一行,包含所求的差。
数据范围:1≤整数长度≤10^5
输入样例:
32
11
输出样例:
21
思路:
这道题主要考察对字符串的模拟,模拟两个整数相减的情况。
来看看我们做减法的情况。(和加法类似)
步骤:
■ 1、用大数的每一位数减去小数的每一位数,每个数从低位到高位依次相减,包括借位。
■ 2、判断当前每个位上的数相减是否小于0。如果小于0往前借一位数,然后当前数加上10,借位置成1。否则不借位,借位置成0。然后算得当前数的结果,存入结果字符串中。
■ 3、循环步骤一和步骤二,直到把字符串遍历完。
■ 4、检查最后字符串中是否包含前导0。如果存在去掉前导0,最后将结果字符串反转。
提示:
■ 1、因为我们不确定最后结果的长度,所以我们常常将得到的每一位结果依次往结果字符串当中增加,这样得到的结果是反的,所以最后我们需要将结果字符串反转。我们可以将输入的两个整数的每一位存入容器中来进行处理。
■ 2、我们处理每个字符串时,从最高位处理,最高位对应的是数字中的最低位。
C++ 代码
#include<iostream>
#include<vector>
using namespace std;
//return A>=B
bool cmp(vector<int>&A,vector<int>&B){
if(A.size()!=B.size()) return A.size()>B.size();
for(int i=A.size()-1;i>=0;i--){
if(A[i]!=B[i])
return A[i]>B[i];
}
return true;
}
vector<int> sub(vector<int>&A,vector<int>&B){
vector<int> res;
int temp=0;
for(int i=0;i<A.size();i++){
temp=A[i]-temp;
if(i<B.size()) temp-=B[i];
res.push_back((temp+10)%10);//当temp>0时,(temp+10)%10=temp。当temp<0,则(temp+10)为当前值,所以将两种情况合并了。
if(temp<0) temp=1;//当temp<0表示借位。
else temp=0;
}
while(res.size()>1&&res.back()==0) res.pop_back();//当情况为:999-999=000,所以去掉前导0
return res;
}
int main(){
string a,b;
cin>>a>>b;
vector<int> A,B;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
if(cmp(A,B)){
vector<int> res=sub(A,B);
for(int i=res.size()-1;i>=0;i--) printf("%d",res[i]); //反向输出,则为结果
}else{
vector<int> res=sub(B,A);
cout<<'-';
for(int i=res.size()-1;i>=0;i--) printf("%d",res[i]);
}
return 0;
}
解决了这道题,可以去解决 MiOJ 3. 大数相减(字符串减法)
43. 字符串相乘
题意:给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
返回值:返回相乘后的结果字符串。
说明:
- 1、num1 和num2 的长度都小于 110
- 2、num1 和num2 都只包含数字 0-9
- 3、num1 和num2 均不以0开头,除非是0本身
- 4、你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式
前言:
对于比较小的数字,我们可以直接将两个数字相乘得到结果。但是本道题的两个字符串的长度小于110,说明有可能达到100以上。所以直接用两数相乘,乘数都有可能无法保存,更不用说要保存结果了。那么我们只能手动模拟字符串相乘,请看以下模拟的情况:
对于手动模拟的思路是,先算789 * 2
,再算789 * 50
,对于789 * 50
直接相当于789 * 5
往后错一位。对于这个过程我们设计了乘法进位,和加法进位。对于三位数乘三位数,有三位数的取值范围为:[100,1000)
,所以三位数乘三位数的取值范围为:[10000,1000000)
。有可能是五位数,有可能是六位数。我们要找到一套简单一致的规则来让计算机计算。我们看789 * 2
,实质是:2 * 9 + 80 * 2 + 700 * 2
,789 * 50
,实质是:50 * 9 + 80 * 9 + 700 * 9
。看以下根据本质计算的结果:
我们通过计算每个数字的每一位和另一个数字的每一位相乘,这样我们就只需要考虑加法和进位,最后加完每一位后就是最终结果了。
思路:
分别用两个指针
( i,j )
在两个数字(num1,num2)
的每一位中循环。res=num1[i] * num2[j]
。每次将结果累加到对应的位置。res对应的位置是str[i+j],str[i+j+1]。
最后得出结果。
C++ 代码
class Solution {
public:
string multiply(string num1, string num2) {
if(num1=="0"||num2=="0") return "0";//当num1或者num2为0时直接返回0
int len1=num1.size(),len2=num2.size();
vector<int> vec(len1+len2);//初始化一个最大的结果容器,里面的内容全为0
string res="";//存储结果
int carry=0;
for(int i=len1-1;i>=0;i--){
for(int j=len2-1;j>=0;j--){
int mul=(num1[i]-'0')*(num2[j]-'0');//每位相乘的结果
int p1=i+j,p2=i+j+1;//相乘后应放到对应的结果[i+j,i+j+1]
int sum=mul+vec[p2];//累加到sum上
vec[p2]=sum%10;
vec[p1]+=sum/10; //加上进位的结果进位
}
}
for(int i=0;i<vec.size();i++){
if(i==0&&vec[i]==0){
continue; //如果第一位为0 说明前缀没有使用,则去掉前缀为0的情况。
}
res.push_back(vec[i]+'0');
}
return res;
}
};