1. 概述

本教程将探讨使用Java计算前N个能被3整除的偶数之和。这个问题可以通过多种方法解决,我们将重点分析两种截然不同的实现方式。

第一种是暴力破解法:通过逐步检查每个偶数是否能被3整除来累加结果。这种方法虽然直观易懂,但当N值较大时效率较低。

第二种是优化数学法:利用能被3整除的偶数的数学特性推导出直接计算公式。这种方法在处理大规模数据时性能优势显著。

2. 暴力破解法

暴力破解法通过遍历数字,筛选出同时满足偶数和能被3整除条件的数进行累加。这种方法效率不高,因为它需要检查每个偶数,而没有直接聚焦于6的倍数(因为任何能同时被2和3整除的数必然是6的倍数)。

2.1. 使用for循环实现

在代码示例中,我们定义NUMBER为7(表示前7个偶数),EXPECTED_SUM为18(6+12)作为预期结果:

static final int NUMBER = 7;
static final int EXPECTED_SUM = 18;

以下使用for循环的实现方式:

@Test
void givenN_whenUsingBruteForceForLoop_thenReturnsCorrectSum() {
    int sum = 0;

    for (int i = 2; i <= NUMBER * 2; i++) {
        if (i % 2 == 0 && i % 3 == 0) {
            sum += i;
        }
    }

    assertEquals(EXPECTED_SUM, sum);
}

这里我们从2开始检查每个偶数,循环持续直到找到前N个满足条件的数。**时间复杂度为O(N)**,因为需要遍历大量不满足条件的数字。

2.2. 函数式编程方法

利用Java的函数式特性可以实现更现代的解决方案:通过Stream API生成无限数字流,先筛选偶数,取前N个,再从中筛选能被3整除的数最后求和。这种声明式风格更简洁:

@Test
void givenN_whenUsingFunctionalApproach_thenReturnsCorrectSum() {
    int sum = IntStream.iterate(2, i -> i + 1)
      .filter(i -> i % 2 == 0)
      .limit(NUMBER)
      .filter(i -> i % 3 == 0)
      .sum();

    assertEquals(EXPECTED_SUM, sum);
}

实现使用IntStream.iterate()生成从2开始的无限整数流,代码简洁且天然支持并行处理。

2.3. 改进的暴力破解法

通过观察能被3整除的偶数必然是6的倍数,我们可以优化算法:不再检查所有偶数,而直接遍历6的倍数。这种优化减少了不必要的检查:

@Test
void givenN_whenUsingImprovedBruteForce_thenReturnsCorrectSum() {
    int sum = IntStream.iterate(6, i -> i + 6)
      .limit(NUMBER / 3)
      .sum();

    assertEquals(EXPECTED_SUM, sum);
}

直接遍历6的倍数显著提升了性能,但时间复杂度仍为线性O(N),因为迭代次数与N成正比。

3. 优化数学法

暴力破解法需要遍历数字并检查是否能被6整除。我们可以利用数学特性进一步优化:目标数列实际是6的倍数,因此无需遍历检查,而是直接计算前N/3个6的倍数之和(因为每3个偶数中只有1个能被3整除)。

3.1. 数学原理

✅ 所有能被3整除的偶数都是6的倍数
✅ 可直接计算前N个6的倍数之和
✅ 前N个6的倍数为:6×1, 6×2, 6×3, ..., 6×N
✅ 求和公式为:Sum = 6 * (1 + 2 + 3 + ⋯ + N)

利用自然数求和公式:

(N * (N + 1)) / 2

前N/3个6的倍数之和可表示为

Sum = 6 * (N / 3 * (N / 3 + 1)) / 2 = 3 * (N / 3) * (N / 3 + 1)

该方法完全避免循环,对大N值效率极高。

3.2. 优化数学实现

直接使用公式计算前N/3个6的倍数之和:

@Test
void givenN_whenUsingOptimizedMethod_thenReturnsCorrectSum() {
    int sum = 3 * (NUMBER / 3) * (NUMBER / 3 + 1);

    assertEquals(EXPECTED_SUM, sum);
}

此方法通过简单算术运算完成计算,时间复杂度为O(1),无论N多大都只需固定次数操作。

4. 两种方法对比

暴力破解法与数学优化法在性能、简洁性和灵活性上存在显著差异:

对比维度 暴力破解法 改进暴力法 数学优化法
时间复杂度 O(N) O(N) O(1)
空间复杂度 O(1) O(1) O(1)
实现简洁性 简单(循环) 高效循环 极简(公式)
灵活性 可适应不同条件 可适应不同条件 公式特定不易修改

核心差异

  • ⚠️ 暴力法需遍历数字(O(N)),数学法直接计算(O(1))
  • ✅ 数学法代码更简洁但需理解数学原理
  • ❌ 数学法灵活性差,修改条件需重新推导公式

5. 总结

本文探讨了计算前N个能被3整除的偶数之和的两种核心方法:暴力破解法(含函数式实现)和数学优化法。暴力法灵活但效率较低(O(N)),数学法通过公式实现常数时间复杂度(O(1)),在大规模计算时优势明显但灵活性不足。

完整源码可在GitHub仓库获取。


原始标题:Sum of First N Even Numbers Divisible by 3 in Java | Baeldung