title: Cells with Odd Values in a Matrix
slug: cells-with-odd-values-in-a-matrix
difficulty: easy
leetcode_id: 1252
leetcode_url: https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/
categories:
  - arrays
  - math
patterns:
  - prefix-sum

function_signature: "def odd_cells(m: int, n: int, indices: list[list[int]]) -> int:"

test_cases:
  visible:
    - input: { m: 2, n: 3, indices: [[0, 1], [1, 1]] }
      expected: 6
    - input: { m: 2, n: 2, indices: [[1, 1], [0, 0]] }
      expected: 0
  hidden:
    - input: { m: 1, n: 1, indices: [[0, 0]] }
      expected: 1
    - input: { m: 3, n: 3, indices: [[0, 0], [1, 1], [2, 2]] }
      expected: 0
    - input: { m: 2, n: 2, indices: [[0, 0]] }
      expected: 3
    - input: { m: 5, n: 5, indices: [[0, 0], [0, 1], [0, 2]] }
      expected: 20
    - input: { m: 3, n: 4, indices: [[0, 0], [1, 1], [0, 1]] }
      expected: 6

description: |
  There is an `m x n` matrix that is initialised to all `0`'s. There is also a 2D array `indices` where each `indices[i] = [r_i, c_i]` represents a **0-indexed location** to perform some increment operations on the matrix.

  For each location `indices[i]`, do **both** of the following:

  1. Increment **all** the cells on row `r_i`.
  2. Increment **all** the cells on column `c_i`.

  Given `m`, `n`, and `indices`, return *the **number of odd-valued cells** in the matrix after applying the increment to all locations in* `indices`.

constraints: |
  - `1 <= m, n <= 50`
  - `1 <= indices.length <= 100`
  - `0 <= r_i < m`
  - `0 <= c_i < n`

examples:
  - input: "m = 2, n = 3, indices = [[0,1],[1,1]]"
    output: "6"
    explanation: "Initial matrix = [[0,0,0],[0,0,0]]. After applying the first increment it becomes [[1,2,1],[0,1,0]]. The final matrix is [[1,3,1],[1,3,1]], which contains 6 odd numbers."
  - input: "m = 2, n = 2, indices = [[1,1],[0,0]]"
    output: "0"
    explanation: "Final matrix = [[2,2],[2,2]]. There are no odd numbers in the final matrix."

explanation:
  intuition: |
    At first glance, this problem seems to require simulating the entire matrix and performing all the increments. However, there's a clever mathematical insight that lets us avoid building the matrix entirely.

    Think of it like this: each cell `(i, j)` in the matrix gets incremented once for every time row `i` appears in `indices`, and once for every time column `j` appears in `indices`. The final value at cell `(i, j)` is simply `row_count[i] + col_count[j]`.

    Now here's the key insight: **a number is odd if and only if it's the sum of an odd and an even number**. If both counts are odd or both are even, their sum is even. If one is odd and one is even, their sum is odd.

    So instead of tracking actual cell values, we only need to count:
    - How many rows have an **odd** increment count
    - How many columns have an **odd** increment count

    A cell is odd exactly when its row has an odd count XOR its column has an odd count. The total count of odd cells is: `(odd_rows × even_cols) + (even_rows × odd_cols)`.

  approach: |
    We can solve this efficiently by counting row and column increments:

    **Step 1: Count increments per row and column**

    - Create arrays `row_count[m]` and `col_count[n]`, initialised to `0`
    - For each `[r, c]` in `indices`, increment `row_count[r]` and `col_count[c]`

    &nbsp;

    **Step 2: Count rows and columns with odd increment counts**

    - `odd_rows`: Count of rows where `row_count[i] % 2 == 1`
    - `odd_cols`: Count of columns where `col_count[j] % 2 == 1`

    &nbsp;

    **Step 3: Calculate the answer using the XOR property**

    - Cells with odd values occur when exactly one of (row count, column count) is odd
    - Formula: `odd_rows × (n - odd_cols) + (m - odd_rows) × odd_cols`
    - This equals `odd_rows × even_cols + even_rows × odd_cols`

    &nbsp;

    **Step 4: Return the result**

    - The formula gives us the exact count of odd-valued cells without building the matrix

  common_pitfalls:
    - title: Building the Entire Matrix
      description: |
        A natural first approach is to create an `m × n` matrix and simulate all the increments. For each index pair, you'd iterate through an entire row (n cells) and an entire column (m cells).

        This leads to **O(k × (m + n))** time where `k` is the number of indices, and **O(m × n)** space for the matrix. While this works for the given constraints, it's inefficient and misses the elegant mathematical solution.
      wrong_approach: "Simulate increments on actual matrix"
      correct_approach: "Count row/column increments and use parity formula"

    - title: Forgetting the XOR Logic
      description: |
        When calculating odd cells, remember that `odd + odd = even` and `even + even = even`. Only `odd + even = odd`.

        A common mistake is to multiply `odd_rows × odd_cols`, which counts cells where *both* are odd — those cells actually have even values!
      wrong_approach: "Count cells where both row and column have odd counts"
      correct_approach: "Count cells where exactly one of row or column has odd count"

    - title: Off-by-One in Even Count Calculation
      description: |
        When computing `even_rows` and `even_cols`, make sure to use `m - odd_rows` and `n - odd_cols` respectively, not `m - 1` or similar.

        The total rows minus odd rows gives even rows. Getting this wrong leads to incorrect final counts.

  key_takeaways:
    - "**Parity insight**: A sum is odd if and only if exactly one addend is odd — this XOR property enables O(1) cell classification"
    - "**Avoid unnecessary simulation**: Count what matters (increments per row/col) rather than simulating every operation"
    - "**Space optimisation**: Instead of O(m × n) matrix, use O(m + n) arrays for row and column counts"
    - "**Mathematical reformulation**: Many simulation problems can be solved by finding the mathematical formula for the final state"

  time_complexity: "O(k + m + n). We iterate through `indices` once (k operations), then through rows (m) and columns (n) to count odd values."
  space_complexity: "O(m + n). We use two arrays to track increment counts for each row and column."

solutions:
  - approach_name: Row and Column Counting
    is_optimal: true
    code: |
      def odd_cells(m: int, n: int, indices: list[list[int]]) -> int:
          # Track how many times each row/column is incremented
          row_count = [0] * m
          col_count = [0] * n

          # Count increments from each index pair
          for r, c in indices:
              row_count[r] += 1
              col_count[c] += 1

          # Count rows and columns with odd increment counts
          odd_rows = sum(1 for count in row_count if count % 2 == 1)
          odd_cols = sum(1 for count in col_count if count % 2 == 1)

          # Cell is odd when exactly one of (row, col) has odd count
          # odd_rows * even_cols + even_rows * odd_cols
          return odd_rows * (n - odd_cols) + (m - odd_rows) * odd_cols
    explanation: |
      **Time Complexity:** O(k + m + n) — One pass through indices, one through rows, one through columns.

      **Space Complexity:** O(m + n) — Two arrays for row and column counts.

      We leverage the insight that a cell's final value equals its row's increment count plus its column's increment count. A cell is odd precisely when one count is odd and the other is even, which we compute using the XOR-like formula.

  - approach_name: Simulation
    is_optimal: false
    code: |
      def odd_cells(m: int, n: int, indices: list[list[int]]) -> int:
          # Create the matrix initialised to zeros
          matrix = [[0] * n for _ in range(m)]

          # Apply each increment operation
          for r, c in indices:
              # Increment entire row r
              for j in range(n):
                  matrix[r][j] += 1
              # Increment entire column c
              for i in range(m):
                  matrix[i][c] += 1

          # Count odd values
          count = 0
          for row in matrix:
              for val in row:
                  if val % 2 == 1:
                      count += 1

          return count
    explanation: |
      **Time Complexity:** O(k × (m + n) + m × n) — For each of k indices, we update m + n cells, then scan entire matrix.

      **Space Complexity:** O(m × n) — Full matrix storage.

      This brute force approach simulates the exact operations described. It's correct but inefficient — we're doing unnecessary work by tracking actual values when we only need parity information. Included to show the progression from naive to optimal solution.
