164 lines
7.0 KiB
YAML
164 lines
7.0 KiB
YAML
title: Check if Every Row and Column Contains All Numbers
|
|
slug: check-if-every-row-and-column-contains-all-numbers
|
|
difficulty: easy
|
|
leetcode_id: 2133
|
|
leetcode_url: https://leetcode.com/problems/check-if-every-row-and-column-contains-all-numbers/
|
|
categories:
|
|
- arrays
|
|
- hash-tables
|
|
patterns:
|
|
- matrix-traversal
|
|
|
|
description: |
|
|
An `n x n` matrix is **valid** if every row and every column contains **all** the integers from `1` to `n` (**inclusive**).
|
|
|
|
Given an `n x n` integer matrix `matrix`, return `true` *if the matrix is **valid***. Otherwise, return `false`.
|
|
|
|
constraints: |
|
|
- `n == matrix.length == matrix[i].length`
|
|
- `1 <= n <= 100`
|
|
- `1 <= matrix[i][j] <= n`
|
|
|
|
examples:
|
|
- input: "matrix = [[1,2,3],[3,1,2],[2,3,1]]"
|
|
output: "true"
|
|
explanation: "In this case, n = 3, and every row and column contains the numbers 1, 2, and 3. Hence, we return true."
|
|
- input: "matrix = [[1,1,1],[1,2,3],[1,2,3]]"
|
|
output: "false"
|
|
explanation: "In this case, n = 3, but the first row and the first column do not contain the numbers 2 or 3. Hence, we return false."
|
|
|
|
explanation:
|
|
intuition: |
|
|
Think of this problem like checking a **simplified Sudoku**. In a valid Sudoku, each row and column must contain every number from 1 to 9 exactly once. Here, we have the same requirement for numbers 1 to n.
|
|
|
|
The core insight is that if a row (or column) of size `n` must contain all numbers from 1 to n, then each number must appear **exactly once**. This means:
|
|
- No duplicates are allowed
|
|
- No numbers outside the range `[1, n]` are allowed (though the constraints guarantee this)
|
|
|
|
A set is the perfect data structure for this check. When you add `n` elements to a set, the set's size will be `n` only if all elements were unique. If there were any duplicates, the size would be smaller.
|
|
|
|
By checking each row and each column against this property, we can determine if the matrix is valid.
|
|
|
|
approach: |
|
|
We solve this using a **Set-Based Validation** approach:
|
|
|
|
**Step 1: Determine the matrix size**
|
|
|
|
- Get `n` from the length of the matrix
|
|
- This tells us each row and column must contain exactly the numbers `1` through `n`
|
|
|
|
|
|
|
|
**Step 2: Validate each row**
|
|
|
|
- For each row in the matrix, convert it to a set
|
|
- Check if the set equals `{1, 2, 3, ..., n}`
|
|
- If any row fails this check, return `false` immediately
|
|
|
|
|
|
|
|
**Step 3: Validate each column**
|
|
|
|
- For each column index `j`, collect all elements `matrix[i][j]` for `i` from `0` to `n-1`
|
|
- Convert this column to a set
|
|
- Check if the set equals `{1, 2, 3, ..., n}`
|
|
- If any column fails this check, return `false` immediately
|
|
|
|
|
|
|
|
**Step 4: Return the result**
|
|
|
|
- If all rows and columns pass validation, return `true`
|
|
|
|
common_pitfalls:
|
|
- title: Checking Only Rows or Only Columns
|
|
description: |
|
|
A matrix might have valid rows but invalid columns (or vice versa).
|
|
|
|
For example, `[[1,2],[1,2]]` has valid rows (both contain `{1, 2}`), but the first column is `{1, 1}` and the second is `{2, 2}` — neither column is valid.
|
|
|
|
Always check **both** rows and columns before returning `true`.
|
|
wrong_approach: "Only validating rows"
|
|
correct_approach: "Validate both rows and columns"
|
|
|
|
- title: Counting Instead of Using Sets
|
|
description: |
|
|
You might try counting occurrences and checking if each number appears exactly once. While this works, it's more complex and error-prone.
|
|
|
|
Using a set is cleaner: if the set of elements equals `{1, 2, ..., n}`, the row/column is valid. This automatically handles duplicate detection and range validation in one check.
|
|
wrong_approach: "Manual counting with arrays"
|
|
correct_approach: "Set comparison for cleaner validation"
|
|
|
|
- title: Not Failing Fast
|
|
description: |
|
|
Some solutions check all rows and columns before deciding validity. This is wasteful — as soon as you find one invalid row or column, you know the entire matrix is invalid.
|
|
|
|
Return `false` immediately when validation fails to optimise performance.
|
|
wrong_approach: "Check everything, then decide"
|
|
correct_approach: "Return false at first failure"
|
|
|
|
key_takeaways:
|
|
- "**Sets for uniqueness**: When checking for duplicates or that all elements in a range are present, sets provide an elegant O(n) solution"
|
|
- "**Matrix traversal pattern**: Accessing columns requires iterating with a fixed column index: `matrix[i][col]` for all rows `i`"
|
|
- "**Fail fast principle**: Return early when you find invalid data rather than completing all checks unnecessarily"
|
|
- "**Simplified Sudoku**: This problem is a building block for understanding more complex grid validation like Sudoku"
|
|
|
|
time_complexity: "O(n^2). We visit each cell exactly twice — once when checking its row and once when checking its column."
|
|
space_complexity: "O(n). We use a set that holds at most `n` elements at any time for validation."
|
|
|
|
solutions:
|
|
- approach_name: Set-Based Validation
|
|
is_optimal: true
|
|
code: |
|
|
def check_valid(matrix: list[list[int]]) -> bool:
|
|
n = len(matrix)
|
|
# The set of numbers that must appear in each row/column
|
|
expected = set(range(1, n + 1))
|
|
|
|
# Check each row
|
|
for row in matrix:
|
|
if set(row) != expected:
|
|
return False
|
|
|
|
# Check each column
|
|
for col in range(n):
|
|
# Collect all elements in this column
|
|
column_set = {matrix[row][col] for row in range(n)}
|
|
if column_set != expected:
|
|
return False
|
|
|
|
return True
|
|
explanation: |
|
|
**Time Complexity:** O(n^2) — We iterate through all n^2 elements twice (once for rows, once for columns).
|
|
|
|
**Space Complexity:** O(n) — The sets we create hold at most n elements.
|
|
|
|
We create the expected set `{1, 2, ..., n}` once, then compare each row and column against it. Using set comprehension for columns keeps the code clean and Pythonic.
|
|
|
|
- approach_name: Early Termination with Size Check
|
|
is_optimal: true
|
|
code: |
|
|
def check_valid(matrix: list[list[int]]) -> bool:
|
|
n = len(matrix)
|
|
|
|
# Check rows - set size must equal n (all unique 1 to n)
|
|
for row in matrix:
|
|
if len(set(row)) != n:
|
|
return False
|
|
|
|
# Check columns
|
|
for col in range(n):
|
|
column_values = set()
|
|
for row in range(n):
|
|
column_values.add(matrix[row][col])
|
|
if len(column_values) != n:
|
|
return False
|
|
|
|
return True
|
|
explanation: |
|
|
**Time Complexity:** O(n^2) — Same as the previous approach.
|
|
|
|
**Space Complexity:** O(n) — Set holds at most n elements.
|
|
|
|
This variant uses size checking instead of set equality. Since the constraints guarantee `1 <= matrix[i][j] <= n`, if we have `n` unique values, they must be exactly `{1, 2, ..., n}`. This avoids creating the expected set but relies on the constraint being enforced.
|