剑指offer(51):不用加减乘除做加法

来源:互联网 发布:2015十大网络流行语 编辑:程序博客网 时间:2024/06/05 13:35

题目描述

写一个函数,求两个整数的和,要求在函数体内不得使用加减乘除四则运算。

分析

对于数字的运算,如果不能使用常规的加减乘除四则运算,那就是能使用位运算了。

考虑十进制下5+17=22的结果。第一步只做各位相加不进位,则相加的结果是12(因为个位上5+7=12,不处理进位的话,认为结果是2;十位上0+1=1结果是1,则十位个位合并的结果是12);第二步处理进位,5+7中有进位,进位的值是10;第三步将两个结果加起来,12+10=22也就是原来5+17=22的结果。

在考虑二进制下的情况5+17=22(10进制)在二进制下101+10001=10110仍然成立。第一步仍然只做各位相加不进位,则结果为10100(最低位的1+1=10,由于不进位,最低位的结果仍然是0);第二步几下进位,这里进位只有最低位相加产生的进位10;第三步,将前两部结果相加,即10100+10=10110

接着考虑用位运算代替前面的加法。第一步不考虑进位的每一位相加,0加0、1加1不考虑进位结果为0,0加1、1加0不考虑进位结果为1,这和异或运算的结果相同;第二步进位的情况是,0加0、0加1、1加0都不会产生进位,只有1加1才进位,这和与运算的结果比较符合,因此这一步可以看成两个数字先做位与运算,然后再向左移动一位;第三步,将前面两个结果相加,这个过程仍然是重复前面两步,知道不产生进位为止。

牛客AC:

/**     * 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。     *      * key:     * 1、位异或运算模拟不考虑进位的加法     * 2、位与运算后左移一位模拟进位     * 3、将前面两步结果相加     * 4、重复运算直到不再产生进位     *      * @param num1     * @param num2     * @return     */    public int add(int num1,int num2) {        int sum = 0, carry = 0;        do {            sum = num1 ^ num2;      // 位异或运算模拟不考虑进位的加法            carry = (num1 & num2) << 1;     // 位与运算后左移一位模拟进位            // 更新赋值,循环将前面两步结果相加            num1 = sum;            num2 = carry;        } while(num2 != 0);     // 重复运算直到不再产生进位        return sum;    }

问题扩展

不适用新的变量,交换两个变量的值。

1、使用加法

/**     * 不使用新的变量交换两个变量     * @param a     * @param b     */    public void swap(int a, int b) {        a = a + b;        b = a - b;  // 即  b = ((a+b) - b) = a        a = a - b;  // 即  a = ((a+b) - a) = b    }

2、使用位异或运算

    /**     * 不使用新的变量交换两个变量     *      * 使用位异或运算     *      * @param a     * @param b     */    public void swap2(int a, int b) {        a = a ^ b;        b = a ^ b;        a = a ^ b;    }

参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社

0 0