LeetCode求1+2+...+n的结果(限定算法条件)

看似一道很简单的题,在LeetCode中却给到了中等难度的定义,主要的原因是题目限制了使用条件:要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

我们先想想常规的解决思路有哪些:如果不限制乘除法的话,我们可以直接使用等差数列求和公式就解决了: ( n + 1 ) ∗ n / 2 (n+1)*n/2 (n+1)n/2。但这个方法最大的问题在于无法通过别的运算法转换乘以n的问题(尽管我们知道乘除可以通过位运算来间接实现,但运算只能限于2的倍数的乘法,如果是乘以3、乘以5或者其他的数字就没办法了)

如果这个题只限定不允许使用乘除的话,其实我们还有别的办法,就是通过循环来将乘法化为加法(利用了乘法的本质),但如果循环也不允许使用呢?我们还可以通过递归方法来实现,但递归到最后还需要条件语句来跳出递归,而这些都是题目所不允许使用的,那么到底应该怎么做呢?

其实这些方法各自都只有一点问题不被满足,我们可以通过别的方法来解决这一点问题。

递归方法

递归方法需要解决的就是转化条件判断语句,这里利用了逻辑运算的短路原理,即A&&B,如果A为Fale,则直接跳过B的判断;同理,A||B,如果A为True,也会直接跳过B的判断。因而,我们就可以利用这样的思想来实现,代码如下:

class Solution {
public:
    int sumNums(int n) {
        n && (n = n + sumNums(n-1));
        return n;
    }
};

由于C++语言中0代表false,非0代表true,因而巧妙的利用n解决了短路判断的条件,可谓十分巧妙!

求和公式法

基于之前的讨论,我们知道公式法需要解决的就是乘以n的问题,而我们目前仅会将2、4、8这样的乘数通过位运算来转换,但对于其他的乘数就无法实现了,所以我们需要将乘法计算从本质上转换为加法。

这里参考了一个叫做俄罗斯农民算法的思想,这个算法原本将乘法用另一种思想进行转换,从而快速得到最终答案,本质上是将被乘数的每一位“贡献值”分布得出,详细的算法不在多做介绍,我们之间进入正题。
有兴趣的同学可以看看这一篇博主的文章

对于 A ∗ B A*B AB这个问题,我们将A和B都转换成二进制,那么B中第 i i i 位对计算结果的贡献值为 A ∗ 2 i = A < < i A*2^i=A<<i A2i=A<<i,因而我们可以按位遍历B的每一位,从而将每一位的贡献值都分别得出,再求和即可(注意到虽然需要遍历,但题目中已经规定了 n n n的范围,即 1 < = n < = 10000 1 <= n <= 10000 1<=n<=10000,所以n最多不会超过14位,我们可以将循环直接转换成14次顺序执行的代码即可)

class Solution {
public:
    int sumNums(int n) {
      int ans = 0, A = n, B = n + 1;

        (B & 1) && (ans += A);
        A <<= 1;
        B >>= 1;
        
        (B & 1) && (ans += A);
        A <<= 1;
        B >>= 1;
        
		...
		//上述代码段重复14次

		return ans>>1;
		//最后右移一位是因为求和公式最后还有一个除以2
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值