《算法零基础100讲》(第27讲) 字符串算法 - 高精度
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法零基础100讲》(第27讲) 字符串算法 - 高精度相关的知识,希望对你有一定的参考价值。
零、写在前面
这是《算法零基础100讲》 专栏打卡学习的第二十七天了。
有不少同学已经不甘心只刷题了,「 解题报告 」 也已经陆续安排上了。每天都会有五六篇高质量的 「 解题报告 」 被我 「 加精 」。如果觉得自己有能力的,也可以来 「 万人千题 」 社区发布你的 「 解题报告 」。千万级流量,你我共同拥有,当然,不忘初心才是最重要滴。
一、概念定义
高精度,是指当一个数无法用程序给定的类型进行表示时,利用数组进行模拟运算的算法。例如,整数12345678912345678912345
已经超过了
64
64
64 位整型,所以我们可以将它存储在数组中,如下:
i i i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
a [ i ] a[i] a[i] | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 2 | 3 | 4 | 5 |
然后就是利用数组来模拟各种运算了。这里只介绍加法和乘法,减法 和 加法类似,除法需要用到二分枚举,暂不介绍。
1、高精度加法
我们把数字按照数位存储到字符串中,加法运算是每一位对应相加,所以当两个字符串长度不一致时,需要对两个字符串进行从后往前遍历相加,为了方便计算,我们首先需要将它逆序,然后就可以顺序从前往后相加了,相加完毕后,需要处理进位,然后再将数位转换成字符。
总结为五步:
1)加数逆序;
2)模拟加法;
3)处理进位;
4)处理前导零;
5)结果逆序;
char * addStrings(char * a, char * b){
char *c;
int lena = strlen(a);
int lenb = strlen(b);
int i, cap, now;
int av, bv;
int maxlen = max(lena, lenb);
inverse(a); // (1)
inverse(b); // (2)
c = (char *)malloc( sizeof(char) * (maxlen + 2) );
cap = 0;
for(i = 0; i < maxlen; ++i) {
av = (i < lena) ? (a[i]-'0') : 0; // (3)
bv = (i < lenb) ? (b[i]-'0') : 0; // (4)
now = (av + bv + cap); // (5)
cap = now / 10; // (6)
c[i] = (now % 10) + '0'; // (7)
}
if(cap) {
c[i] = '1'; // (8)
maxlen ++;
}
c[maxlen] = '\\0';
inverse(c); // (9)
return c;
}
- ( 1 ) − ( 2 ) (1) - (2) (1)−(2) 分别对两个加数进行逆序存储;
- ( 3 ) (3) (3) 第一个加数转换成整数的形式,高位不够补0;
- ( 4 ) (4) (4) 第二个加数转换成整数的形式,高位不够补0;
- ( 5 ) (5) (5) 两个加数相加,并且带上前一位的进位;
- ( 6 ) (6) (6) 处理当前位的进位;
- ( 7 ) (7) (7) 将数位转换成字符;
- ( 8 ) (8) (8) 处理加法后产生的最高位的进位;
- ( 9 ) (9) (9) 最后,再进行一次逆序,高位和低位互换;
2、高精度乘法
乘法和加法类似,也是采用字符串存储,首先将两个乘数的数位进行逆序,根据乘法的定义,第
i
i
i 位 和 第
j
j
j 位相乘以后,作用的位是在
i
+
j
i+j
i+j 位上,直接累加即可,最后再统一处理进位,消除前导零,并且处理正好是零的情况。总结为五步:
1)乘数逆序;
2)模拟乘法;
3)处理进位;
4)处理前导零;
5)结果逆序;
char * multiply(char * a, char * b){
int i, j, num;
int lena = strlen(a);
int lenb = strlen(b);
int len = lena + lenb;
int *cnum = (int *)malloc( sizeof(int) * (len+5) );
char *c = (char *)malloc( sizeof(char) * (len+5) );
memset( cnum, 0, sizeof(int) * (len+5) );
inverse(a); // (1)
inverse(b); // (2)
for(i = 0; i < lena; ++i) {
for(j = 0; j < lenb; ++j) { // (3)
cnum[i+j] += (a[i] - '0') * (b[j] - '0');
}
}
for(i = 0; i < len; ++i) { // (4)
cnum[i+1] += cnum[i] / 10;
cnum[i] %= 10;
}
++len;
while(len > 1 && !cnum[len-1]) { // (5)
--len;
}
for(i = 0; i < len; ++i) { // (6)
c[i] = cnum[i] + '0';
}
c[len] = '\\0';
inverse(c); // (7)
return c;
}
- ( 1 ) − ( 2 ) (1) - (2) (1)−(2) 分别对两个乘数进行逆序存储;
- ( 3 ) (3) (3) 模拟乘法;
- ( 4 ) (4) (4) 处理进位;
- ( 5 ) (5) (5) 处理前导零;
- ( 6 ) (6) (6) 转换成字符;
- ( 7 ) (7) (7) 再进行一次逆序,高位和低位互换;
二、题目描述
给定两个二进制字符串,返回它们的和(用二进制表示)。输入为 非空 字符串且只包含数字 1 和 0。
三、算法详解
模拟高精度加法,进位时进行模二处理即可。
四、源码剖析
void swap(char *a, char *b) {
char tmp = *a;
*a = *b;
*b = tmp;
}
int max(int a, int b) {
return a > b ? a : b;
}
void inverse(char *a) { // (1)
int i, len = strlen(a);
for(i = 0; i < len/2; ++i) {
swap(&a[i], &a[len-1-i]);
}
}
char * addBinary(char *a, char *b){ // (2)
char *c;
int lena = strlen(a);
int lenb = strlen(b);
int i, cap, now;
int av, bv;
int maxlen = max(lena, lenb);
inverse(a);
inverse(b);
c = (char *)malloc( sizeof(char) * (maxlen + 2) );
cap = 0;
for(i = 0; i < maxlen; ++i) {
av = (i < lena) ? (a[i]-'0') : 0;
bv = (i < lenb) ? (b[i]-'0') : 0;
now = (av + bv + cap);
cap = now / 2;
c[i] = (now % 2) + '0';
}
if(cap) {
c[i] = '1';
maxlen ++;
}
c[maxlen] = '\\0';
inverse(c);
return c;
}
- ( 1 ) (1) (1) 实现字符串逆序;
- ( 2 ) (2) (2) 类似上文提到的高精度加法;
五、推荐专栏
六、习题练习
序号 | 题目链接 | 难度 |
---|---|---|
1 | 千位分隔数 | ★☆☆☆☆ |
2 | 字符串转化后的各位数字之和 | ★☆☆☆☆ |
3 | 字符串中第二大的数字 | ★☆☆☆☆ |
4 | 最小时间差 | ★☆☆☆☆ |
5 | 罗马数字转整数 | ★★☆☆☆ |
6 | 整数转罗马数字 | ★★☆☆☆ |
7 | 字符串压缩 | ★★☆☆☆ |
8 | 字符串相加 | ★★★☆☆ |
9 | 二进制求和 | ★★★☆☆ |
10 | 检查某单词是否等于两单词之和 | ★★★☆☆ |
11 | 字符串相乘 | ★★★☆☆ |
12 | 数字转英文 | ★★★☆☆ |
以上是关于《算法零基础100讲》(第27讲) 字符串算法 - 高精度的主要内容,如果未能解决你的问题,请参考以下文章
《算法零基础100讲》(第25讲) 字符串算法 - 字符串反转
《算法零基础100讲》(第24讲) 字符串算法 - 字符计数法
题解《算法零基础100讲》(第26讲) 字符串算法 - 回文串(java版)