On this page
2352. Equal Row and Column Pairs
Ledger row shapes with Counter, then build each column and query the ledger.
Given a 0-indexed n x n integer matrix grid, return the number of pairs (ri, cj) such that row ri and column cj are equal.
A row and column pair is considered equal if they contain the same elements in the same order (i.e., an equal array).
- Input:
- grid = [[3,2,1],[1,7,6],[2,7,7]]
- Output:
- 1
- Explanation:
- There is 1 equal row and column pair: (Row 2, Column 1): [2,7,7].
- Input:
- grid = [[3,1,2,2],[1,4,4,5],[2,4,2,2],[2,4,2,2]]
- Output:
- 3
- Explanation:
- There are 3 equal row and column pairs: (Row 0, Column 0): [3,1,2,2]; (Row 2, Column 2): [2,4,2,2]; (Row 3, Column 2): [2,4,2,2].
- n == grid.length == grid[i].length
- 1 <= n <= 200
- 1 <= grid[i][j] <= 10^5
Order matters: [2,7,7] matches [2,7,7] only, not [7,2,7]. Duplicate-looking rows each form their own pairs.
Understand the problem — what are we counting?
You're given a square grid of numbers. Count how many rows look exactly like some column.
Take this 3×3 example:
(row 0) 3 2 1
(row 1) 1 7 6
(row 2) 2 7 7
Row: (3, 2, 1), (1, 7, 6), (2, 7, 7)
Col: (3, 1, 2), (2, 7, 7), (1, 6, 7)
Bottom row (2, 7, 7) = middle column (2, 7, 7) → 1 pairApproach — keep a ledger
Comparing every row against every column is slow and messy. Better: two phases.
- Phase 1 "ledger": scan every row and record "this shape appeared how many times?"
- Phase 2 "check": for each column, ask the ledger "does this shape exist?" If yes, add that count to the score
Add row_count[col], not just +1 — duplicate rows each pair with this column. Counter returns 0 for missing keys, so you won’t get a KeyError.
Walkthrough — ledger and columns
After phase 1 the ledger is {(3, 2, 1): 1, (1, 7, 6): 1, (2, 7, 7): 1}. Then for j in range(n) build each column:
| j | col built | ask the ledger | pairs so far |
|---|---|---|---|
| 0 | (3, 1, 2) | missing → 0 | 0 |
| 1 | (2, 7, 7) | hit → 1 | 1 |
| 2 | (1, 6, 7) | missing → 0 | 1 |
Loop ends with pairs = 1 — exact match.
Try it yourself first
Ledger and walkthrough table are above — write it yourself, then open the fold below when stuck or ready to compare.
Solution code · folded so you can try firstพับไว้ด้านใน — คลิกเมื่อพร้อมดู
Core: ledger row shapes in a Counter, then build each column and query — add the count, not +1.
from collections import Counter
def equal_pairs(grid):
# --- Phase 1: ledger the rows ---
n = len(grid)
row_count = Counter(tuple(row) for row in grid)
# {(3, 2, 1): 1, (1, 7, 6): 1, (2, 7, 7): 1}
pairs = 0
# --- Phase 2: build each column and query the ledger ---
for j in range(n):
# lock column j, let row i walk top → bottom
col = tuple(grid[i][j] for i in range(n))
pairs += row_count[col]
return pairs
print(equal_pairs([[3, 2, 1], [1, 7, 6], [2, 7, 7]])) # 1
print(equal_pairs([[3, 1, 2, 2], [1, 4, 4, 5],
[2, 4, 2, 2], [2, 4, 2, 2]])) # 31
3What to notice
- tuple(row) — lists can’t be dict keys; forget the conversion and it crashes
- col = tuple(grid[i][j] for i in range(n)) locks column j and walks row i top → bottom
- pairs += row_count[col] adds every matching row count, not just +1
- Counter returns 0 for missing keys — no need for if key in … before adding
col = tuple(grid[i][j] for i in range(n)) # j = 0 → (3, 1, 2)Time O(n²) one pass over rows + one pass building columns · Space O(n²) storing all row tuples in the Counter
When matching identical items across two groups, don’t compare every pair. Count one group into a hash map, then query the other one by one. Remember: list/row as a key → convert to tuple first. Trap: add row_count[col], not +1.