剑指Offer 64、65 不寻常的计算

80 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

题目:本文还是有两题:

  1. 1+2+3+...+n。在运算过程中不能使用乘除法、forwhileifelseswitchcase等关键字及条件判断语句(A?B:C)
  2. 不用加减乘除做加法。计算两数之和,要求不能使用四则运算。

解题思路

说实话,两题都是端午想放松一下,但还是要卷一篇水文,以此来迷惑颓废的心灵。。。。。毫无意外,未遂,卒~

回到本题,本题常规思路就显得没意义了,无非就是遍历数组或者使用递归的方法。但遍历数组用了for,而递归需要判断递归结束的条件,即使用了if,既然解题思路只有这两种,那肯定是从其中一种进行修改,修改的方法通过感觉是使用位运算。遍历数组显然无法修改,那可能性只能是递归了,我们首先来看一下常规递归怎么解决本题:

public int sumNums(int n) {
    if(n<=0) return 0;
    return sumNums(n-1) + n;
}

此方法不满足条件的只有第一个判断的地方,我们需要判断n是否满足条件从而决定是否向下继续执行,即只需要在不满足条件时阻塞递归的n-1即可。

通过这个特性,可以想到截断位运算,当A&&BA \&\& BAAfalsefalse的时候,将不会判断BB,但我们需要让BB的表达式完成加n1n-1后的结果,可得代码如下:

public int sumNums(int n) {
    boolean flag = n >=0 && (n += sumNums(n-1))>0;
    return n;
}

接下来来看第二问,计算两数之和,不使用加减法,本题还是使用位运算,需要知道的前缀知识是:

  1. 两个数非进位和,则采用异或运算。
  2. 两个数进位,则采用与运算+左移一位

可得代码如下:

public int add(int a, int b) {
    if(a == 0) return b;
    int base = a ^ b;
    int up = a & b;
    return add(up<<1,base);
}