分类求和并作差

标签: 数学

难度: Easy

给你两个正整数 nm

现定义两个整数 num1num2 ,如下所示:

  • num1:范围 [1, n] 内所有 无法被 m 整除 的整数之和。
  • num2:范围 [1, n] 内所有 能够被 m 整除 的整数之和。

返回整数 num1 - num2

示例 1:

输入:n = 10, m = 3
输出:19
解释:在这个示例中:
- 范围 [1, 10] 内无法被 3 整除的整数为 [1,2,4,5,7,8,10] ,num1 = 这些整数之和 = 37 。
- 范围 [1, 10] 内能够被 3 整除的整数为 [3,6,9] ,num2 = 这些整数之和 = 18 。
返回 37 - 18 = 19 作为答案。

示例 2:

输入:n = 5, m = 6
输出:15
解释:在这个示例中:
- 范围 [1, 5] 内无法被 6 整除的整数为 [1,2,3,4,5] ,num1 = 这些整数之和 =  15 。
- 范围 [1, 5] 内能够被 6 整除的整数为 [] ,num2 = 这些整数之和 = 0 。
返回 15 - 0 = 15 作为答案。

示例 3:

输入:n = 5, m = 1
输出:-15
解释:在这个示例中:
- 范围 [1, 5] 内无法被 1 整除的整数为 [] ,num1 = 这些整数之和 = 0 。 
- 范围 [1, 5] 内能够被 1 整除的整数为 [1,2,3,4,5] ,num2 = 这些整数之和 = 15 。
返回 0 - 15 = -15 作为答案。

提示:

  • 1 <= n, m <= 1000

Submission

运行时间: 22 ms

内存: 16.0 MB

class Solution:
    def differenceOfSums(self, n: int, m: int) -> int:
        ans = (1 + n) * n // 2
        diff = 0
        cur = m
        while cur <= n:
            diff += cur
            cur += m
        return ans - 2 * diff

Explain

该题解首先计算1到n之间所有整数的总和,这可以通过等差数列求和公式 (1 + n) * n / 2 来完成。接着,作者使用一个循环来求解1到n之间所有能被m整除的整数之和。循环变量cur从m开始,每次增加m,直到超过n为止。每次循环,将cur加到一个累加器diff中。最后,题解返回所有数的总和减去能被m整除的数的总和的两倍,得到的就是所有不能被m整除的数的总和减去能被m整除的数的总和。

时间复杂度: O(n/m)

空间复杂度: O(1)

class Solution:
    def differenceOfSums(self, n: int, m: int) -> int:
        # 计算从1到n的所有整数的和
        ans = (1 + n) * n // 2
        diff = 0  # 初始化被m整除的数的总和
        cur = m  # 从m开始
        while cur <= n:  # 当当前数不超过n时循环
            diff += cur  # 将当前数加到diff
            cur += m  # 将cur增加m
        # 返回所有数的总和减去被m整除的数的总和的两倍
        return ans - 2 * diff

Explore

在这个算法中,首先计算的是1到n所有整数的总和。然后,计算能被m整除的整数之和。如果我们直接从总和中减去能被m整除的整数之和,得到的是不能被m整除的整数之和。但题目要求的是不能被m整除的整数之和减去能被m整除的整数之和,因此需要再减去一次能被m整除的整数之和,即总和减去两倍的能被m整除的数之和。这样处理是为了符合题目的要求,计算出正确的差值。

确实有一种更高效的方法来计算能被m整除的数的和,而不需要逐个累加。可以使用等差数列的求和公式来直接计算。设k是n除以m的商(即n/m的整数部分),则能被m整除的数是m, 2m, 3m, ..., km。这是一个首项为m,公差也为m,项数为k的等差数列。等差数列求和公式是(首项 + 末项)* 项数 / 2,所以和为(m + km)* k / 2。这种方法只需进行常数次计算,比循环累加每个能被m整除的数要效率更高。

当m大于n时,范围[1, n]内没有任何一个数能被m整除,因此能被m整除的整数之和为0。在这种情况下,num2(能被m整除的数的和)为0。因此,num1(无法被m整除的整数之和)就等于1到n的总和,即用等差数列求和公式(1 + n) * n / 2计算。最后,返回的结果就是num1 - num2,即num1 - 0 = num1。这意味着在m大于n的情况下,直接返回1到n的总和即可。