189 lines
8.5 KiB
YAML
189 lines
8.5 KiB
YAML
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]`
|
||
|
||
|
||
|
||
**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`
|
||
|
||
|
||
|
||
**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`
|
||
|
||
|
||
|
||
**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.
|