九度 题目1003:A+B

题目

题目描述:

给定两个整数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. 如果两个数字符号相同, 则进行加法, 所得结果符号与任一加数符号相同; 如果两个数字符号相反, 则进行减法, 所得结果符号与绝对值较大的加数符号相同.
    1). 对于第一种情况, 从两数字最低位 (字符串最后一位) 开始相加, 依次向前, 注意对进位的处理. 处理完公共长度后, 需要对某一较长的数字的剩余部分进行处理.
    2). 对于第二种情况, 让指针pa指向绝对值较大的数, pb指向绝对值较小的数, 注意字符串长度要与之保持对应. 然后对两者的绝对值进行相减, 所得结果非负, 最终符号由绝对值较大的数字决定.
  3. 对于结果数组中的前导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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值