Medium | 剑指 Offer 64. 求1+2+…+n | 位运算
剑指 Offer 64. 求1+2+…+n
求 1+2+...+n
,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
限制:
1 <= n <= 10000
解题思路
这是一道考验知识储备的题目。高斯小学就告诉我们, 首尾相加乘以个数除以二结果就出来了。我们小学就知道, 这是最简单最快捷的方法。现在题目把路堵死了, 那该怎么解决。毫无疑问, 这道题的所有解决办法都是效率不高的办法, 所以这道题并不追求效率。目的就是看你肚子有多少知识储备, 看你能想出多少种解决办法。
先看能使用的运算符, 把运算符数一遍, 还可以用的运算符有加法, 减法, 与, 或, 非, 移位。
方法一:递归
public int sumNums(int n) {
boolean flag = n > 0 && (n += sumNums(n - 1)) > 0;
return n;
}
方法二: 俄罗斯农民乘法
这道题第一反应就是 n * (n + 1) / 2
,除2可以通过移位来实现 n * (n + 1) >> 1
,那么乘法有没有办法通过其他方式实现呢?只使用加法和移位就可以实现, 以下是原理。
A * B可以把B写作二进制的形式, 即B = 2^0 + 2^1 + 2^2 + ... 2^n 的形式, 那么A * B 可以写作 A * 2^0.... A* 2 ^ n, 当然这里面有些系数是0, 我这图方便没有写。所以通过二进制表示和位运算, 可以先看B有有哪些位是1的, 对于是1的位, 将A左移, 左移的距离就是这个位数。然后将这些左移之后的数字进行相加即可。理论上有32个位, 要将32个位逐个判断进行相加。题目规定了N不超过10000, 所以也就14位。下面是硬编码的代码.
class Solution {
public int sumNums(int n) {
int ans = 0, A = n, B = n + 1;
boolean flag;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
flag = ((B & 1) > 0) && (ans += A) > 0;
A <<= 1;
B >>= 1;
return ans >> 1;
}
}