【每日一题Day350】LC2652倍数求和 | 数学+容斥原理

倍数求和【LC2652】

给你一个正整数 n ,请你计算在 [1,n] 范围内能被 357 整除的所有整数之和。

返回一个整数,用于表示给定范围内所有满足约束条件的数字之和。

暴力枚举

  • 思路

    枚举 [ 1 , n ] [1,n] [1,n]范围内每个数,判断是否能被 357 整除,如果能则累加结果

  • 实现

    class Solution {
        public int sumOfMultiples(int n) {
            int res = 0;
            for (int i = 1; i <= n; i++){
                if (i % 3 == 0 || i % 5 == 0 || i % 7 == 0){
                    res += i;
                }
            }
            return res;
        }
    }
    
    • 复杂度分析

      • 时间复杂度: O ( n ) O(n) O(n)
      • 空间复杂度: O ( 1 ) O(1) O(1)

从倍数出发

  • 优化思路:借鉴埃氏筛

    • [ 1 , n ] [1,n] [1,n]中有许多数不需要进行判断,我们可以从3、5、7的倍数出发,如果其在 [ 1 , n ] [1,n] [1,n]范围内,那么累加该数
    • 在统计的过程中要避免重复统计, 3 ∗ i 1 3*i_1 3i1 5 ∗ i 2 5*i_2 5i2 7 ∗ i 3 7*i_3 7i3可能指向同一个数
      • 方法1:使用哈希表记录已经统计过的数
      • 方法2:规定统计先后顺序,如果 i i i不能整除3,再判断 5 ∗ i 5*i 5i是否在范围内;如果 i i i不能整除3和5,再判断 7 ∗ i 7*i 7i是否在范围内
        • 如果 i i i中包含因子3,那么对于 i ∗ 5 = j ∗ 3 ∗ 5 i*5=j*3*5 i5=j35,在 i ′ = i / 3 ∗ 5 i'=i/3*5 i=i/35会统计该数
  • 实现

    class Solution {
        public int sumOfMultiples(int n) {
            int res = 0;
            int i = 1;       
            while (i * 3 <= n){
                res += i * 3;
                // 避免重复计算 如果i中包含因子3,那么i*5=j*3*5,在i'=i/3*5会统计该数
                if (i % 3 != 0){
                    if (i * 5 <= n){
                        res += i * 5;
                    }
                    if (i % 5 != 0 && i * 7 <= n){
                        res += i * 7;
                    }
                }
                // if (i % 3 != 0 && i * 5 <= n){
                //     res += i * 5;
                // }
                // if (i % 3 != 0 && i % 5 != 0 && i * 7 <= n){
                //     res += i * 7;
                // }
                i++;
                
            }
            return res;
        }
    }
    
    • 复杂度分析

      • 时间复杂度: O ( log ⁡ n ) O(\log n) O(logn)
      • 空间复杂度: O ( 1 ) O(1) O(1)

数学+容斥原理

  • 思路

    • 定义函数 f ( x , n ) f(x,n) f(x,n) [ 1 , n ] [1,n] [1,n]中能被 x x x整除的数之和,那么一共有 m = ⌊ n / x ⌋ m=\lfloor n/x \rfloor m=n/x个数能被 x x x整数,组成首项为 x x x、末项为 x m xm xm的等差数列,和为
      f ( x ) = ( x + m x ) ∗ m 2 f(x)=\frac {(x+mx)*m}{2} f(x)=2(x+mx)m

    • 根据容斥原理,能被 357 整除的所有数之和为
      f ( 3 , n ) + f ( 5 , n ) + f ( 7 , n ) − f ( 3 ∗ 5 , n ) − f ( 3 ∗ 7 , n ) − f ( 5 ∗ 7 , n ) + f ( 3 ∗ 5 ∗ 7 , n ) ; f(3,n) + f(5,n) + f(7,n) - f(3*5,n) - f(3*7,n) - f(5*7,n) + f(3*5*7,n); f(3,n)+f(5,n)+f(7,n)f(35,n)f(37,n)f(57,n)+f(357,n);

  • 实现

    class Solution {
        public int sumOfMultiples(int n) {
            return f(3,n) + f(5,n) + f(7,n) - f(3*5,n) - f(3*7,n) - f(5*7,n) + f(3*5*7,n);
        }
        public int f(int x, int n){
            int m = n / x;
            return (x + m * x) * m / 2;
        }
    }
    
    • 复杂度分析

      • 时间复杂度: O ( 1 ) O(1) O(1)
      • 空间复杂度: O ( 1 ) O(1) O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值