面试题 47(*),不用加减乘除做加法(位运算易想到,怎么用就是个技术活了)(附 不定义新变量前提下交换两数的方法)

用位运算是第一反应,a^b可以算出当前位的结果, a&b可以算出是否进位。

但是接下来怎么办呢?

我的方法是,每次从两个数取一位,然后计算,进位。直到两个数都没有位可取了(往左看都只有0),最后做一个进位。

我的代码:

#include <stdio.h>

int Sum(int a, int b){
    int finalRes = 0;
    int count = 0;
    int prevAcc = 0, curAcc= 0;
    int p = 0, q = 0;
    int bitRes = 0;
    while(a | b){
        p = a&1; q = b&1;
        a = a >> 1; b = b >> 1;
        int temp = p ^ q;
        curAcc = p & q;
        bitRes = temp ^ prevAcc;
        prevAcc = curAcc | (temp&prevAcc);
        finalRes |= (bitRes << (count++));
    }
    finalRes |= prevAcc << count;
    return finalRes;
}

// ====================测试代码====================
void Test(int num1, int num2, int expected)
{
    int result = Sum(num1, num2);
    if(result == expected)
        printf("%d + %d is %d. Passed\n", num1, num2, result);
    else
        printf("%d + %d is %d. Failed\n", num1, num2, result);
}

int main()
{
    Test(1, 2, 3);
    Test(111, 899, 1010);

    Test(5, 2, 7);
    Test(1, 100, 101);

    Test(3, 0, 3);
    Test(0, 5, 5);

    Test(2, 8, 10);
}

白板一次error free bug free,但是,写到一半就明白这个解法是不全面的。。

因为没有考虑负数。

补码表示下的负数,并不能通过每次提取一位的方法来倒腾。

这种思路对于上次facebook的面试题倒是可以用,当时的题目是:两个只含有'0' '1'的字符串,计算两个字符串相加的结果。

在这种情况下,答案的解法确实让人佩服。

书上代码:

int Add(int num1, int num2)
{
    int sum, carry;
    do
    {
        sum = num1 ^ num2;
        carry = (num1 & num2) << 1;

        num1 = sum;
        num2 = carry;
    }
    while(num2 != 0);

    return num1;
}

整体计算,carry表示各个位上计算后的进位,将carry左移一位,再加上sum,就是要求的结果。如何算carry和sum相加的结果呢?

同样可以利用上述方法。

循环思路出现。

循环终止条件是carry为0,也就是说,不再有进位了。

 

引申:

顺便提一提怎样在不定义新的变量的情况下交换两个int的方法。假设要交换a和b。

四则运算法,这个比较熟悉了。

a = a + b;

b = a - b;

a = a - b;

位运算法,不常用,但是更简单:

a = a ^ b;

b = a ^ b;

a = a ^ b;

 

posted on 2014-03-11 10:09  Felix Fang  阅读(439)  评论(0编辑  收藏  举报

导航