title: Average Value of Even Numbers That Are Divisible by Three
slug: average-value-of-even-numbers-divisible-by-three
difficulty: easy
leetcode_id: 2455
leetcode_url: https://leetcode.com/problems/average-value-of-even-numbers-that-are-divisible-by-3/
categories:
  - arrays
  - math
patterns:
  - slug: prefix-sum
    is_optimal: true

function_signature: "def average_value(nums: list[int]) -> int:"

test_cases:
  visible:
    - input: { nums: [1, 3, 6, 10, 12, 15] }
      expected: 9
    - input: { nums: [1, 2, 4, 7, 10] }
      expected: 0
  hidden:
    - input: { nums: [6] }
      expected: 6
    - input: { nums: [6, 12, 18] }
      expected: 12
    - input: { nums: [1, 2, 3, 4, 5] }
      expected: 0
    - input: { nums: [6, 6, 6, 6] }
      expected: 6
    - input: { nums: [12, 24, 36, 48, 60] }
      expected: 36
    - input: { nums: [5, 7, 11, 13, 17, 19] }
      expected: 0
    - input: { nums: [6, 12, 1, 2, 3, 18] }
      expected: 12

description: |
  Given an integer array `nums` of **positive** integers, return *the average value of all even integers that are divisible by* `3`.

  Note that the **average** of `n` elements is the **sum** of the `n` elements divided by `n` and **rounded down** to the nearest integer.

constraints: |
  - `1 <= nums.length <= 1000`
  - `1 <= nums[i] <= 1000`

examples:
  - input: "nums = [1,3,6,10,12,15]"
    output: "9"
    explanation: "6 and 12 are even numbers that are divisible by 3. (6 + 12) / 2 = 9."
  - input: "nums = [1,2,4,7,10]"
    output: "0"
    explanation: "There is no single number that satisfies the requirement, so return 0."

explanation:
  intuition: |
    This problem asks us to filter numbers by two conditions and then compute their average.

    Think of it like sorting through a basket of numbered balls: we only want to pick the balls that satisfy **two criteria simultaneously**. A number must be:
    1. **Even** — divisible by 2
    2. **Divisible by 3**

    Here's the key insight: a number that is both even (divisible by 2) AND divisible by 3 must be divisible by their least common multiple, which is **6**. So instead of checking two conditions, we can simplify to checking just one: is the number divisible by 6?

    Once we've identified all qualifying numbers, we sum them up and divide by the count. If no numbers qualify, we return 0.

  approach: |
    We solve this using a **Single Pass with Running Sum** approach:

    **Step 1: Initialise tracking variables**

    - `total`: Set to `0` to accumulate the sum of qualifying numbers
    - `count`: Set to `0` to track how many numbers qualify

    &nbsp;

    **Step 2: Iterate through the array**

    - For each number, check if it's divisible by 6 (`num % 6 == 0`)
    - If yes, add it to `total` and increment `count`

    &nbsp;

    **Step 3: Calculate and return the average**

    - If `count` is `0`, return `0` (no qualifying numbers)
    - Otherwise, return `total // count` (integer division for rounded-down average)

    &nbsp;

    This approach processes each element exactly once, making it efficient and straightforward.

  common_pitfalls:
    - title: Checking Two Conditions Separately
      description: |
        A common approach is to check `num % 2 == 0 and num % 3 == 0` separately. While correct, this is slightly more verbose than necessary.

        Since even numbers divisible by 3 are exactly the numbers divisible by 6 (LCM of 2 and 3), you can simplify to `num % 6 == 0`.
      wrong_approach: "Check num % 2 == 0 and num % 3 == 0"
      correct_approach: "Check num % 6 == 0"

    - title: Forgetting the Empty Case
      description: |
        If no numbers in the array satisfy the conditions, dividing by zero will cause an error.

        For example, with `nums = [1, 2, 4, 7, 10]`, no number is divisible by 6. You must check if `count == 0` before dividing and return `0` in that case.
      wrong_approach: "Return total / count without checking count"
      correct_approach: "Return 0 if count is 0, else total // count"

    - title: Using Float Division Instead of Integer Division
      description: |
        The problem specifies the average should be **rounded down** to the nearest integer. Using `/` in Python returns a float, while `//` performs integer division (floor division).

        For `(6 + 12) / 2`, Python's `/` gives `9.0`, but `//` gives `9`. The problem expects an integer result.
      wrong_approach: "total / count (float division)"
      correct_approach: "total // count (integer division)"

  key_takeaways:
    - "**Simplify conditions with LCM**: When checking divisibility by multiple numbers, consider using their LCM. Even AND divisible by 3 = divisible by 6."
    - "**Handle empty results**: Always check for division by zero when computing averages or ratios."
    - "**Integer vs float division**: Use `//` for floor division when the problem asks for rounded-down results."
    - "**Single pass efficiency**: Accumulating sum and count in one pass is O(n) and avoids storing filtered elements."

  time_complexity: "O(n). We iterate through the array once, checking each element and updating our running totals."
  space_complexity: "O(1). We only use two variables (`total` and `count`), regardless of input size."

solutions:
  - approach_name: Single Pass with Divisibility Check
    is_optimal: true
    code: |
      def average_value(nums: list[int]) -> int:
          # Track sum and count of qualifying numbers
          total = 0
          count = 0

          for num in nums:
              # Even AND divisible by 3 = divisible by 6
              if num % 6 == 0:
                  total += num
                  count += 1

          # Avoid division by zero; return 0 if no qualifying numbers
          return total // count if count > 0 else 0
    explanation: |
      **Time Complexity:** O(n) — Single pass through the array.

      **Space Complexity:** O(1) — Only two integer variables used.

      We iterate once, checking each number for divisibility by 6 (the LCM of 2 and 3). This combines the "even" and "divisible by 3" checks into one operation. We accumulate the sum and count, then compute the floor-divided average.

  - approach_name: Filter and Sum
    is_optimal: false
    code: |
      def average_value(nums: list[int]) -> int:
          # Filter to get all numbers divisible by 6
          qualifying = [num for num in nums if num % 6 == 0]

          # Return 0 if no qualifying numbers, else compute average
          if not qualifying:
              return 0
          return sum(qualifying) // len(qualifying)
    explanation: |
      **Time Complexity:** O(n) — Two passes: one for filtering, one for summing.

      **Space Complexity:** O(k) — Where k is the number of qualifying elements.

      This approach is more readable by separating the filtering and averaging steps. However, it uses extra space to store the filtered list. For this problem's constraints (n <= 1000), the difference is negligible, but the single-pass approach is more memory-efficient.
