题目
题目描述:
给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号”,”隔开。
现在请计算A+B的结果,并以正常形式输出。
输入:
输入包含多组数据数据,每组数据占一行,由两个整数A和B组成(-10^9 < A,B < 10^9)。
输出:
请计算A+B的结果,并以正常形式输出,每组数据占一行。
样例输入:
-234,567,890 123,456,789
1,234 2,345,678
样例输出:
-111111101
2346912
来源:
2010年浙江大学计算机及软件工程研究生机试真题
分析
该题与2616年3月28日阿里内推笔试第一题很相似, 区别在于阿里那道题要求处理大数, 而且数字之间没有”,”. 下面的分析与解法将考虑存在大数的情况.
- 因为输入字符串中存在逗号, 因此先对两个字符串进行预处理. 分配新的数组, 在对原指针数组遍历的过程中将逗号去除, 复制到新的数组.
- 如果两个数字符号相同, 则进行加法, 所得结果符号与任一加数符号相同; 如果两个数字符号相反, 则进行减法, 所得结果符号与绝对值较大的加数符号相同.
1). 对于第一种情况, 从两数字最低位 (字符串最后一位) 开始相加, 依次向前, 注意对进位的处理. 处理完公共长度后, 需要对某一较长的数字的剩余部分进行处理.
2). 对于第二种情况, 让指针pa
指向绝对值较大的数,pb
指向绝对值较小的数, 注意字符串长度要与之保持对应. 然后对两者的绝对值进行相减, 所得结果非负, 最终符号由绝对值较大的数字决定. - 对于结果数组中的前导0需要跳过.
解答
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_LEN 3000
void do_calc(char *a, char *b)
{
int nega, negb, neg=0;
nega = (a[0] == '-' ? 1 : 0);
negb = (b[0] == '-' ? 1 : 0);
char *pa = ((*a == '+' || *a == '-') ? (a+1) : (a));
char *pb = ((*b == '+' || *b == '-') ? (b+1) : (b));
// the length of the number part
int lena = strlen(pa);
int lenb = strlen(pb);
char result[MAX_LEN];
memset(result, 0, sizeof(char) *(MAX_LEN));
int k = 0;
if ((nega && negb) || (!nega && !negb)) {
int carry = 0;
// both neg. or pos. do addition, the sign is the same
// as either operand
if (nega && negb){
neg = 1; // both are neg. so the result is also neg.
}
int i = lena - 1;
int j = lenb - 1;
while (i >= 0 && j >= 0) {
int tmp = (pa[i--]-'0') + (pb[j--]-'0') + carry;
int digit = tmp % 10;
carry = tmp / 10;
result[k++] = digit+'0';
}
// if either operand has some digits left
while (i >= 0) {
int tmp = pa[i--] - '0' + carry;
int digit = tmp % 10;
carry = tmp / 10;
result[k++] = digit +'0';
}
while (j >= 0) {
int tmp = pb[j--] - '0' + carry;
int digit = tmp % 10;
carry = tmp / 10;
result[k++] = digit +'0';
}
if (carry > 0) {
result[k++] = carry + '0';
}
} else {
// different sign, do minus
int borrowed = 0;
if (lena < lenb || (lena == lenb && strcmp(pa, pb) == -1)) {
// make pa point to the one with bigger abs. value
char *ctmp = pa;
pa = pb; pb = ctmp;
int lentmp = lena;
lena = lenb; lenb = lentmp;
// conceptually negativity should also be swaped, but we can
// just assign negb to neg and omit the negativity swap
neg = negb;
} else {
neg = nega;
}
int i = lena-1;
int j = lenb-1;
while (i >=0 && j>=0) {
int tmp = (pa[i--] - '0') - (pb[j--] - '0');
if (borrowed) {
tmp -= 1;
}
if (tmp < 0) {
tmp += 10;
borrowed = 1;
} else {
borrowed = 0;
}
result[k++] = tmp % 10 + '0';
}
// pa points the larger number, so only one while
while (i >= 0) {
int tmp = pa[i--] - '0';
if (borrowed) {
tmp -= 1;
}
if (tmp < 0) {
tmp += 10;
borrowed = 1;
} else {
borrowed = 0;
}
result[k++] = tmp % 10 + '0';
}
}
// k points to one element past the last element, so we go back
k--;
while (k > 0 && result[k] == '0')
k--; // skip leading zeros
if (k == 0 && result[k] == '0') {
printf("0\n"); // the result is zero, print and exit
return ;
}
if (neg) {
printf("-");
}
while (k >= 0) {
printf("%c", result[k]);
k--;
}
printf("\n");
}
void add_number(char *a, char *b)
{
char a2[MAX_LEN];
char b2[MAX_LEN];
char *pa = a, *pa2 = a2;
char *pb = b, *pb2 = b2;
// preprocess to remove ","
while (*pa) {
if (*pa != ',') {
*pa2++ = *pa;
}
pa++;
}
*pa2 = '\0';
while (*pb) {
if (*pb != ',') {
*pb2++ = *pb;
}
pb++;
}
*pb2 = '\0';
do_calc(a2, b2);
}
int main()
{
char a[MAX_LEN];
char b[MAX_LEN];
while (scanf("%s %s", a, b) != EOF) {
add_number(a, b);
}
}