Solution 1Three Passes

  • TimeO(1)
  • SpaceO(1)

Strictly O(1): the board is fixed at 9x9, so the work is pinned at 243 cell visits
(81 x 3 passes) and no set ever exceeds 9 entries. That label fits any correct solution though, brute force included, so the useful form is the generalised one: on an n x n board this is O(n^2) time, which is linear in the input (the input IS n^2 cells) and therefore optimal, with O(n) space.

Three passes costs 3x the cell reads of the single-pass [hash-set] version below, but holds one set alive at a time instead of 3n of them, O(n) space against O(n^2).
At 9x9 both collapse to O(1), but the trade is real on a generalised board.

Pitfalls

'.' is added to dup unconditionally, so the sets fill with dots. That is harmless only because board[r][c] != '.' is evaluated first and short-circuits before the membership test can ever fire on a dot. A continue on '.' would say it directly

Solved in 14m

class Solution:
    '''
    Time Complexity: O(1)
    Space Complexity: O(1)
    Pitfalls: '.' is added to `dup` unconditionally, so the sets fill with dots. That is harmless only because `board[r][c] != '.'` is evaluated first and short-circuits before the membership test can ever fire on a dot. A `continue` on '.' would say it directly.

    Strictly O(1): the board is fixed at 9x9, so the work is pinned at 243 cell visits
    (81 x 3 passes) and no set ever exceeds 9 entries. That label fits any correct
    solution though, brute force included, so the useful form is the generalised one:
    on an n x n board this is O(n^2) time, which is linear in the input (the input IS
    n^2 cells) and therefore optimal, with O(n) space.

    Three passes costs 3x the cell reads of the single-pass [hash-set] version below,
    but holds one set alive at a time instead of 3n of them, O(n) space against O(n^2).
    At 9x9 both collapse to O(1), but the trade is real on a generalised board.
    '''
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        for r in range(9):
            dup = set()
            for c in range(9):
                if board[r][c] != '.' and board[r][c] in dup:
                    return False
                dup.add(board[r][c])

        for c in range(9):
            dup = set()
            for r in range(9):
                if board[r][c] != '.' and board[r][c] in dup:
                    return False
                dup.add(board[r][c])

        for ra in [0, 3, 6]:
            for ca in [0, 3, 6]:
                dup = set()
                for r in range(ra, ra+3):
                    for c in range(ca, ca+3):
                        if board[r][c] != '.' and board[r][c] in dup:
                            return False
                        dup.add(board[r][c])

        return True
Leet Code/python.py · L241–282
public boolean isValidSudoku(char[][] board) {
    for (int i = 0; i < 9; i++) {
        int[] rowDuplicates = new int[10];
        for (int j = 0; j < 9; j++) {
            if (board[i][j] != '.') {
                if (rowDuplicates[board[i][j] - '0'] > 0) {
                    return false;
                }
                rowDuplicates[board[i][j] - '0']++;
            }
        }
    }
    for (int i = 0; i < 9; i++) {
        int[] colDuplicates = new int[10];
        for (int j = 0; j < 9; j++) {
            if (board[j][i] != '.') {
                if (colDuplicates[board[j][i] - '0'] > 0) {
                    return false;
                }
                colDuplicates[board[j][i] - '0']++;
            }
        }
    }
    for (int i = 0; i < 9; i+=3) {
        for (int j = 0; j < 9; j+=3) {
            int[] boxDuplicates = new int[10];
            for (int r = i; r < i + 3; r++) {
                for (int c = j; c < j + 3; c++) {
                    if (board[r][c] != '.') {
                        if (boxDuplicates[board[r][c] - '0'] > 0) {
                            return false;
                        }
                        boxDuplicates[board[r][c] - '0']++;
                    }
                }
            }
        }
    }
    return true;
}
Leet Code/java.java · L186–226

Solution 2Hash Set

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        boxes = [[set() for _ in range(3)] for _ in range(3)]
        col = [set() for _ in range(9)]
        for i in range(9):
            row = set()
            for j in range(9):
                num = board[i][j]
                if num == ".": continue
                if num in row or num in col[j] or num in boxes[i//3][j//3]: return False
                row.add(num)
                col[j].add(num)
                boxes[i//3][j//3].add(num)
        return True
Leet Code/python.py · L285–299
public boolean isValidSudoku2(char[][] board) {
    for (int i=0; i<9; i++) {
        Set<Character> row = new HashSet<>();
        Set<Character> col = new HashSet<>();
        Set<Character> box = new HashSet<>();
        for (int j=0; j<9; j++) {
            if (board[i][j] != '.' && !row.add(board[i][j])) {
                return false;
            }
            if (board[j][i] != '.' && !col.add(board[j][i])) {
                return false;
            }
            if (board[3*(i/3) + j/3][3*(i%3) + j%3] != '.' && !box.add(board[3*(i/3) + j/3][3*(i%3) + j%3])) {
                return false;
            }
        }
    }
    return true;
}
Leet Code/java.java · L227–246

Solution 3Count Array

Java
public boolean isValidSudoku3(char[][] board) {
    for (int i=0; i<9; i++) {
        int[] row = new int[9];
        int[] col = new int[9];
        int[] box = new int[9];
        for (int j=0; j<9; j++) {
            if (board[i][j] != '.') {
                if(row[board[i][j] - '1'] > 0) {
                    return false;
                }
                row[board[i][j] - '1']++;
            }
            if (board[j][i] != '.') {
                if(col[board[j][i] - '1'] > 0) {
                    return false;
                }
                col[board[j][i] - '1']++;
            }
            int r = 3*(i/3) + j/3;
            int c = 3*(i%3) + j%3;
            if (board[r][c] != '.') {
                if (box[board[r][c] - '1'] > 0) {
                    return false;
                }
                box[board[r][c] - '1']++;
            }
        }
    }
    return true;
}
Leet Code/java.java · L247–277