算法-不使用加减法符号实现两数相加减,两种实现方式

Leetcode-371

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。

示例 1:

输入: a = 1, b = 2
输出: 3
示例 2:

输入: a = -2, b = 3
输出: 1

1、不使用加减法符号实现加法(I)

看到大佬们给出的代码的确很简洁,但是同样的,也很难懂,这里给出一种非常直观的解法
主要思路:
1、从1<<0到1<<31做掩码,遍历一下,分别与a和b按位与,检测对应位
2、如果对应位都为1,那么进一位:result|=mask<<1;
3、如果对应位只有一个为1,且result在当前位为0,那么将当前位置1
4、如果对应位只有一个为1,且result在当前位为1,那么将当前位置0,再进1位
5、返回result

    public int getSum1(int a, int b) {
    
    
        int result=0;
        for(int i=0;i<32;i++){
    
    
            int mask=1<<i;
            if((a&mask)!=0&&(b&mask)!=0){
    
    //两个都是1,必然进位
                result|=mask<<1;
            }else if(!(((a&mask)==0)&&((b&mask)==0))){
    
    
                if((result&mask)==0){
    
    
                    result|=mask;
                }else{
    
    
                    result&=~mask;//清除原来位
                    result|=mask<<1;//进一位
                }
            }
        }
        return result;
    }

上面的写法其实是没有问题的,虽然得到mask的时候使用到了++运算符。
++运算符对应的汇编指令映射到X86后其实是INC,而+映射的是ADD。但++看起来还是有点不顺眼。

为了避免这种比较尴尬情况,我们其实可以换个思路,mask其实是可以由自身得到的,即每轮循环过后,mask=mask<<1;直到mask==1<<31的时候终止循环。这样我们就得到一个纯位运算得到的加法。


    public int getSum(int a, int b) {
    
    
        int result=0;
        int mask=0;
        while(true){
    
    
            mask=mask==0?1:mask<<1;
            if((a&mask)!=0&&(b&mask)!=0){
    
    //两个都是1,必然进位
                result|=mask<<1;
            }else if(!(((a&mask)==0)&&((b&mask)==0))){
    
    //其中某一个为1
                if((result&mask)==0){
    
    //如果现在位是0,那么将现在位变成1
                    result|=mask;
                }else{
    
    //如果现在位是1,那么要将当前位置0,高位放置1
                    result&=~mask;//清除原来位
                    result|=mask<<1;//进一位
                }
            }
            if(mask==1<<31){
    
    
                break;
            }
        }
        return result;
    }

2、不使用加减法符号实现加法(II)

大佬们给出的简洁代码如下所示:

    public int getSum(int a, int b) {
    
    
    	while (b != 0) {
    
    
            int temp=a^b;//无进位累加值
            int carry=(a&b)<<1;//进位值
            //a=无进位累加值 b=进位值
            a=temp;
            b=carry;
        }
        return a;
    }

简单解释一下:
1、无进位的加法使用异或实现
2、进位值为a和b的最高位决定,两个最高位均为1,则进1位,而a和b的最高位可以由a&b获得,这比较好理解,然后如果他们的最高位按位与的结果为最高位1,那么向左再移动一位,即为进位。直到进位为0,说明运算结束。

3、不使用加减法符号实现减法

如何实现减法呢?这就要考虑到正负数的转换问题了,负数=正数按位取反+1

    public int getSub(int a, int b) {
    
    
    	b=~b;//获得-b
    	b++;
    	while (b != 0) {
    
    
            int temp=a^b;//无进位累加值
            int carry=(a&b)<<1;//进位值
            //a=无进位累加值 b=进位值
            a=temp;
            b=carry;
        }
        return a;
    }

猜你喜欢

转载自blog.csdn.net/qq_23594799/article/details/105324292
今日推荐