【刷题笔记】LeetCode_67:二进制求和_简单(C)

题目:二进制求和

给你两个二进制字符串,返回它们的和(用二进制表示)。

输入为 非空 字符串且只包含数字 1 和 0。

示例 1:

输入: a = “11”, b = “1”
输出: “100”

示例 2:

输入: a = “1010”, b = “1011”
输出: “10101”

提示:

每个字符串仅由字符 '0' 或 '1' 组成。
1 <= a.length, b.length <= 10^4
字符串如果不是 "0" ,就都不含前导零。

这道题乍一看很容易的样子,我刚开始是将二进制数字转化为十进制做的,好不容易把逻辑上的各种BUG都改对,常规的用例都没问题,但是数据溢出…于是我把所有int都改成long long,还是溢出。。遂放弃这个方法。
参考其他大神的代码,发现转化为十进制无论如何都会有数据溢出的问题,所以就直接用满2进制的方法做。如下是一个比较普通的方法,但对我来说是最好理解的。。。

char*  addBinary(char * a, char * b){

    char *ret = (char*)malloc(sizeof(char)* 5000);
    memset(ret,0x00,sizeof(ret));
    
    int len_a = strlen(a);
    int len_b = strlen(b);
    int len;
    int carry = 0;
    int numa,numb,sum;
    if(len_a > len_b) len = len_a;
    else len = len_b;

    ret[len+1] = '\0';

    for(--len_a,--len_b; len >=0; len_a--,len_b--,len--)
    {
        if(len_a < 0) numa = 0; //假如a是空字符串
        else numa = a[len_a] - '0';

        if(len_b < 0) numb = 0;
        else numb = b[len_b] - '0';

        sum = numa + numb + carry;
        carry = sum / 2;
        ret[len] = sum % 2 + '0';
    }
    
    if(ret[0] == '0') return &ret[1];
    else return &ret[0];
   
}

个人觉得这道题的key是想清楚,a,b字符串数组中只有’0’和’1’两种情况,sum只有’0’,‘1’,'2’三种情况,carry只有0和1两种情况,以及sum如果为2,carry赋值1,ret为‘0’。

1.位数。大部分用例的结果的位数都是比用例本身多一位的(也最多就多一位),如:“11”,“1”,最终结果为“100”,这是因为满2就向前进一位。处理方法是,先获取a,b中更长的那个字符串的长度,即len;创建字符串数组ret,在"Len+1"的位置赋值’\0’。这是因为数组下标是0-len-1,但我们需要留出一位用来处理结果位数比用例多一位的情况。注意:创建ret的时候先memset一下,全部初始化为‘0’,这样最后return的时候可以判断首位是否为’0’,若为’0’则说明没有发生这种情况,这个位置没有用,则从1位置返回,如果不为’0’则说明这种情况已发生,从首位返回。
2.对齐相加。因为要从个位数,即最后一位开始相加,故初始值设定为–len_a,–len_b。如果len_a或者len_b小于0了,说明这个字符串已经空了,该位置就补0。
3.进位和答案字符的处理。carry代表进位,如果sum>=2就为1,否则为0。非常巧妙的可以用sum/2表示,因为如果sum只有0,1,2三种可能,小于2的话sum/2就是0,等于2就是1。还有ret,也是三种情况,0,1,2,如果为2,则要进位,本位赋予0,其它情况无变化。所以可以用sum%2来处理,小于2的和2取余数就是其本身,等于2取余数则为0。

你可能感兴趣的:(刷题笔记)