187 lines
8.1 KiB
YAML
187 lines
8.1 KiB
YAML
title: Check if Matrix Is X-Matrix
|
||
slug: check-if-matrix-is-x-matrix
|
||
difficulty: easy
|
||
leetcode_id: 2319
|
||
leetcode_url: https://leetcode.com/problems/check-if-matrix-is-x-matrix/
|
||
categories:
|
||
- arrays
|
||
- math
|
||
patterns:
|
||
- slug: matrix-traversal
|
||
is_optimal: true
|
||
|
||
function_signature: "def check_x_matrix(grid: list[list[int]]) -> bool:"
|
||
|
||
test_cases:
|
||
visible:
|
||
- input: { grid: [[2, 0, 0, 1], [0, 3, 1, 0], [0, 5, 2, 0], [4, 0, 0, 2]] }
|
||
expected: true
|
||
- input: { grid: [[5, 7, 0], [0, 3, 1], [0, 5, 0]] }
|
||
expected: false
|
||
hidden:
|
||
- input: { grid: [[1, 0, 1], [0, 1, 0], [1, 0, 1]] }
|
||
expected: true
|
||
- input: { grid: [[1, 0, 0], [0, 1, 0], [0, 0, 1]] }
|
||
expected: false
|
||
- input: { grid: [[0, 0, 1], [0, 1, 0], [1, 0, 0]] }
|
||
expected: false
|
||
- input: { grid: [[5, 0, 5], [0, 5, 0], [5, 0, 5]] }
|
||
expected: true
|
||
|
||
description: |
|
||
A square matrix is said to be an **X-Matrix** if **both** of the following conditions hold:
|
||
|
||
1. All the elements in the diagonals of the matrix are **non-zero**.
|
||
2. All other elements are `0`.
|
||
|
||
Given a 2D integer array `grid` of size `n x n` representing a square matrix, return `true` *if* `grid` *is an X-Matrix*. Otherwise, return `false`.
|
||
|
||
constraints: |
|
||
- `n == grid.length == grid[i].length`
|
||
- `3 <= n <= 100`
|
||
- `0 <= grid[i][j] <= 10^5`
|
||
|
||
examples:
|
||
- input: "grid = [[2,0,0,1],[0,3,1,0],[0,5,2,0],[4,0,0,2]]"
|
||
output: "true"
|
||
explanation: "The diagonal elements (positions where i == j or i + j == n - 1) are all non-zero: 2, 1, 3, 1, 5, 2, 4, 2. All other elements are 0. Thus, grid is an X-Matrix."
|
||
- input: "grid = [[5,7,0],[0,3,1],[0,5,0]]"
|
||
output: "false"
|
||
explanation: "The element at position (0,1) is 7, which should be 0 since it's not on a diagonal. Also, position (1,2) is 1 instead of 0. Thus, grid is not an X-Matrix."
|
||
|
||
explanation:
|
||
intuition: |
|
||
Imagine drawing a large "X" across a square grid. The "X" touches the four corners and crosses in the center. These positions form the **two diagonals** of the matrix:
|
||
|
||
- **Primary diagonal**: runs from top-left to bottom-right (where row index equals column index: `i == j`)
|
||
- **Anti-diagonal**: runs from top-right to bottom-left (where row plus column equals `n - 1`: `i + j == n - 1`)
|
||
|
||
Think of it like this: you're a quality inspector checking each cell of the grid. At every position, you need to answer one question: "Am I on a diagonal?" If yes, the value must be non-zero. If no, the value must be zero.
|
||
|
||
The key insight is that determining whether a position `(i, j)` lies on a diagonal is a simple mathematical check — no need to pre-compute or store the diagonal positions. This allows us to verify the X-Matrix property in a single pass through the grid.
|
||
|
||
approach: |
|
||
We solve this using a **Single Pass Matrix Traversal**:
|
||
|
||
**Step 1: Iterate through every cell**
|
||
|
||
- Use nested loops to visit each position `(i, j)` in the grid
|
||
- For each cell, determine if it lies on a diagonal
|
||
|
||
|
||
|
||
**Step 2: Check diagonal membership**
|
||
|
||
- A cell `(i, j)` is on the primary diagonal if `i == j`
|
||
- A cell `(i, j)` is on the anti-diagonal if `i + j == n - 1`
|
||
- Combined: a cell is on *some* diagonal if `i == j` or `i + j == n - 1`
|
||
|
||
|
||
|
||
**Step 3: Validate the cell value**
|
||
|
||
- If the cell is on a diagonal: check that `grid[i][j] != 0`
|
||
- If the cell is NOT on a diagonal: check that `grid[i][j] == 0`
|
||
- If any check fails, immediately return `false`
|
||
|
||
|
||
|
||
**Step 4: Return the result**
|
||
|
||
- If we complete the traversal without finding any violations, return `true`
|
||
|
||
|
||
|
||
This approach works because we exhaustively check every cell exactly once, ensuring both conditions of the X-Matrix definition are satisfied.
|
||
|
||
common_pitfalls:
|
||
- title: Forgetting the Anti-Diagonal
|
||
description: |
|
||
A common mistake is only checking the primary diagonal (`i == j`) and forgetting that the anti-diagonal (`i + j == n - 1`) is also part of the "X" shape.
|
||
|
||
For example, in a 3x3 grid, position `(0, 2)` and `(2, 0)` are on the anti-diagonal but not the primary diagonal. Missing this check would incorrectly require these cells to be zero.
|
||
wrong_approach: "Only checking i == j for diagonals"
|
||
correct_approach: "Check both i == j and i + j == n - 1"
|
||
|
||
- title: Off-By-One in Anti-Diagonal Check
|
||
description: |
|
||
The anti-diagonal condition is `i + j == n - 1`, not `i + j == n`. Remember that indices are 0-based, so for an `n x n` matrix, the anti-diagonal connects positions like `(0, n-1)`, `(1, n-2)`, ..., `(n-1, 0)`.
|
||
|
||
If you use `i + j == n`, you'll be checking positions that don't exist or missing the actual anti-diagonal.
|
||
wrong_approach: "Using i + j == n for anti-diagonal"
|
||
correct_approach: "Use i + j == n - 1 for anti-diagonal"
|
||
|
||
- title: Checking Only One Condition
|
||
description: |
|
||
Both conditions must be checked for every cell:
|
||
- Diagonal cells must be **non-zero**
|
||
- Non-diagonal cells must be **zero**
|
||
|
||
Some solutions only verify that diagonals are non-zero, forgetting to check that everything else is zero, or vice versa.
|
||
wrong_approach: "Only checking diagonals are non-zero, ignoring other cells"
|
||
correct_approach: "Verify both conditions: diagonals non-zero AND others zero"
|
||
|
||
key_takeaways:
|
||
- "**Diagonal identification**: In an `n x n` matrix, primary diagonal positions satisfy `i == j`, anti-diagonal positions satisfy `i + j == n - 1`"
|
||
- "**Early exit optimisation**: Return `false` immediately upon finding any violation rather than checking all cells first"
|
||
- "**Matrix traversal pattern**: Nested loops with `O(n^2)` complexity are acceptable when you must inspect every cell"
|
||
- "**Simple validation problems**: When verifying properties, translate the definition directly into conditional checks"
|
||
|
||
time_complexity: "O(n^2). We visit each of the n × n cells exactly once to verify its value."
|
||
space_complexity: "O(1). We only use a constant amount of extra space for loop variables and comparisons."
|
||
|
||
solutions:
|
||
- approach_name: Single Pass Validation
|
||
is_optimal: true
|
||
code: |
|
||
def check_x_matrix(grid: list[list[int]]) -> bool:
|
||
n = len(grid)
|
||
|
||
for i in range(n):
|
||
for j in range(n):
|
||
# Check if this position is on either diagonal
|
||
on_diagonal = (i == j) or (i + j == n - 1)
|
||
|
||
if on_diagonal:
|
||
# Diagonal elements must be non-zero
|
||
if grid[i][j] == 0:
|
||
return False
|
||
else:
|
||
# Non-diagonal elements must be zero
|
||
if grid[i][j] != 0:
|
||
return False
|
||
|
||
# All checks passed
|
||
return True
|
||
explanation: |
|
||
**Time Complexity:** O(n^2) — We iterate through all n × n cells once.
|
||
|
||
**Space Complexity:** O(1) — Only a few variables used regardless of input size.
|
||
|
||
We check each cell exactly once. For diagonal positions (where `i == j` or `i + j == n - 1`), we verify the value is non-zero. For all other positions, we verify the value is zero. Any violation causes an immediate return of `false`.
|
||
|
||
- approach_name: Condensed Boolean Check
|
||
is_optimal: true
|
||
code: |
|
||
def check_x_matrix(grid: list[list[int]]) -> bool:
|
||
n = len(grid)
|
||
|
||
for i in range(n):
|
||
for j in range(n):
|
||
on_diagonal = (i == j) or (i + j == n - 1)
|
||
# XOR-like logic: diagonal and non-zero, or not diagonal and zero
|
||
if on_diagonal != (grid[i][j] != 0):
|
||
return False
|
||
|
||
return True
|
||
explanation: |
|
||
**Time Complexity:** O(n^2) — Same traversal as the first approach.
|
||
|
||
**Space Complexity:** O(1) — Constant extra space.
|
||
|
||
This condensed version uses a clever boolean comparison. The condition `on_diagonal != (grid[i][j] != 0)` returns `True` (invalid) when:
|
||
- The cell is on a diagonal but has value 0, OR
|
||
- The cell is not on a diagonal but has a non-zero value
|
||
|
||
Both cases represent violations of the X-Matrix property.
|