150NeetCode 150

7.Valid Sudoku

MediumArrays & Hashing ยท 7/9

Problem

Determine whether a partially filled 9 x 9 Sudoku board is valid. Only the filled cells need to be checked, against three rules:

  1. Each row contains the digits 1-9 at most once.
  2. Each column contains the digits 1-9 at most once.
  3. Each of the nine 3 x 3 sub-boxes contains the digits 1-9 at most once.

Empty cells are marked '.'. A valid board is not necessarily solvable โ€” we only check that no rule is currently broken.

Examples

Input:  board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
Explanation: No row, column or 3x3 box repeats a digit.
Input:  board = the same board, but board[0][0] = "8" instead of "5"
Output: false
Explanation: Column 0 now has two 8s (rows 0 and 3), and the top-left box also has two 8s (board[0][0] and board[2][2]).

Constraints

  • board.length == 9
  • board[i].length == 9
  • board[i][j] is a digit '1'-'9' or '.'.

๐Ÿ’ก Key Insight

Every filled cell belongs to exactly one row, one column and one box, and the box index is (r / 3) * 3 + (c / 3). If we keep a "seen" record per row, per column and per box, a single pass over the 81 cells detects any repeat the moment it appears. Because digits are only 1-9, those records can be tiny boolean arrays or even bit masks.

Three Separate Passes

TimeO(81) = O(1)SpaceO(9) = O(1)

Intuition

Check each rule independently: scan all rows, then all columns, then all boxes. For each unit, use a fresh HashSet and report a duplicate if a digit is added twice.

Algorithm

  1. For each row r: new set; for each c, if the cell is a digit and already in the set, return false.
  2. For each column c: same, iterating over r.
  3. For each box b (0..8): its top-left is (3 * (b / 3), 3 * (b % 3)); scan the 9 cells with a new set.
  4. Return true.

Visualization

Box numbering (b) and top-left cell:

 b=0 (0,0) | b=1 (0,3) | b=2 (0,6)
 b=3 (3,0) | b=4 (3,3) | b=5 (3,6)
 b=6 (6,0) | b=7 (6,3) | b=8 (6,6)

Code

java
import java.util.HashSet;
import java.util.Set;

class Solution {
    public boolean isValidSudoku(char[][] board) {
        // Rule 1: rows
        for (int r = 0; r < 9; r++) {
            Set<Character> seen = new HashSet<>();
            for (int c = 0; c < 9; c++) {
                char ch = board[r][c];
                if (ch != '.' && !seen.add(ch)) {
                    return false;
                }
            }
        }
        // Rule 2: columns
        for (int c = 0; c < 9; c++) {
            Set<Character> seen = new HashSet<>();
            for (int r = 0; r < 9; r++) {
                char ch = board[r][c];
                if (ch != '.' && !seen.add(ch)) {
                    return false;
                }
            }
        }
        // Rule 3: 3x3 boxes
        for (int b = 0; b < 9; b++) {
            Set<Character> seen = new HashSet<>();
            int startRow = (b / 3) * 3;
            int startCol = (b % 3) * 3;
            for (int r = startRow; r < startRow + 3; r++) {
                for (int c = startCol; c < startCol + 3; c++) {
                    char ch = board[r][c];
                    if (ch != '.' && !seen.add(ch)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

Complexity

  • Time: O(81) = O(1) โ€” each cell is visited three times. For an n x n board this is O(nยฒ).
  • Space: O(9) = O(1) โ€” one set of at most 9 digits at a time.

Complexity Comparison

Approach Time Space
Three Separate Passes O(1) (3 ร— 81 cells) O(1)
One Pass with Hash Sets O(1) (81 cells) O(1) (up to 243 entries)
One Pass with Bit Masks O(1) (81 cells) O(1) (27 ints)

Common Pitfalls

  • Wrong box index: r / 3 + c / 3 collides (e.g. boxes (0,1) and (1,0) both give 1). It must be (r / 3) * 3 + c / 3.
  • Treating '.' as a value โ€” adding it to a set reports a false duplicate on the second empty cell.
  • Trying to solve the board. Validity only means no current conflicts; an unsolvable but conflict-free board is still valid.
  • Using ch - '0' as a shift amount gives bits 1..9; that works too, but mixing it with ch - '1' elsewhere causes silent mismatches.