def solveSudoku(board):
rows = [set() for _ in range(9)]
cols = [set() for _ in range(9)]
boxes = [set() for _ in range(9)]
empties = []
for i in range(9):
for j in range(9):
if board[i][j] == '.':
empties.append((i,j))
else:
val = board[i][j]
rows[i].add(val)
cols[j].add(val)
boxes[(i//3)*3 + j//3].add(val)
def get_candidates(r, c):
b = (r//3)*3 + c//3
return [ch for ch in '123456789' if ch not in rows[r] and ch not in cols[c] and ch not in boxes[b]]
def backtrack():
if not empties:
return True
# Choose empty cell with fewest candidates
empties.sort(key=lambda x: len(get_candidates(x[0], x[1])))
r, c = empties.pop(0)
b = (r//3)*3 + c//3
for ch in get_candidates(r, c):
board[r][c] = ch
rows[r].add(ch)
cols[c].add(ch)
boxes[b].add(ch)
if backtrack():
return True
board[r][c] = '.'
rows[r].remove(ch)
cols[c].remove(ch)
boxes[b].remove(ch)
empties.insert(0, (r, c))
return False
backtrack()
# Example usage:
if __name__ == '__main__':
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"]
]
solveSudoku(board)
for row in board:
print(row)
Line Notes
def get_candidates(r, c):Helper to get all valid digits for cell (r,c)
empties.sort(key=lambda x: len(get_candidates(x[0], x[1])))Sort empties by fewest candidates to pick most constrained cell
r, c = empties.pop(0)Choose cell with fewest options
for ch in get_candidates(r, c):Try all valid digits for chosen cell
empties.insert(0, (r, c))Backtrack by reinserting cell if no digit fits
rows[r].add(ch)Mark digit used in row
board[r][c] = '.'Reset cell on backtrack
import java.util.*;
public class SudokuSolver {
private Set<Character>[] rows = new HashSet[9];
private Set<Character>[] cols = new HashSet[9];
private Set<Character>[] boxes = new HashSet[9];
private List<int[]> empties = new ArrayList<>();
public void solveSudoku(char[][] board) {
for (int i = 0; i < 9; i++) {
rows[i] = new HashSet<>();
cols[i] = new HashSet<>();
boxes[i] = new HashSet<>();
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j];
if (c == '.') {
empties.add(new int[]{i, j});
} else {
rows[i].add(c);
cols[j].add(c);
boxes[(i/3)*3 + j/3].add(c);
}
}
}
backtrack(board);
}
private List<Character> getCandidates(int r, int c) {
List<Character> candidates = new ArrayList<>();
int b = (r/3)*3 + c/3;
for (char ch = '1'; ch <= '9'; ch++) {
if (!rows[r].contains(ch) && !cols[c].contains(ch) && !boxes[b].contains(ch)) {
candidates.add(ch);
}
}
return candidates;
}
private boolean backtrack(char[][] board) {
if (empties.isEmpty()) return true;
empties.sort(Comparator.comparingInt(a -> getCandidates(a[0], a[1]).size()));
int[] pos = empties.remove(0);
int r = pos[0], c = pos[1];
int b = (r/3)*3 + c/3;
for (char ch : getCandidates(r, c)) {
board[r][c] = ch;
rows[r].add(ch);
cols[c].add(ch);
boxes[b].add(ch);
if (backtrack(board)) return true;
board[r][c] = '.';
rows[r].remove(ch);
cols[c].remove(ch);
boxes[b].remove(ch);
}
empties.add(0, pos);
return false;
}
public static void main(String[] args) {
SudokuSolver solver = new SudokuSolver();
char[][] 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'}
};
solver.solveSudoku(board);
for (char[] row : board) {
System.out.println(Arrays.toString(row));
}
}
}
Line Notes
private List<Character> getCandidates(int r, int c)Returns valid digits for cell (r,c)
empties.sort(Comparator.comparingInt(a -> getCandidates(a[0], a[1]).size()));Sort empties by fewest candidates
int[] pos = empties.remove(0);Choose most constrained cell
for (char ch : getCandidates(r, c))Try all valid digits
empties.add(0, pos);Backtrack by reinserting cell
rows[r].add(ch);Mark digit used in row
board[r][c] = '.';Reset cell on backtrack
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;
class Solution {
vector<unordered_set<char>> rows, cols, boxes;
vector<pair<int,int>> empties;
public:
void solveSudoku(vector<vector<char>>& board) {
rows = vector<unordered_set<char>>(9);
cols = vector<unordered_set<char>>(9);
boxes = vector<unordered_set<char>>(9);
empties.clear();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j];
if (c == '.') {
empties.emplace_back(i, j);
} else {
rows[i].insert(c);
cols[j].insert(c);
boxes[(i/3)*3 + j/3].insert(c);
}
}
}
backtrack(board);
}
vector<char> getCandidates(int r, int c) {
vector<char> candidates;
int b = (r/3)*3 + c/3;
for (char ch = '1'; ch <= '9'; ch++) {
if (rows[r].count(ch) == 0 && cols[c].count(ch) == 0 && boxes[b].count(ch) == 0) {
candidates.push_back(ch);
}
}
return candidates;
}
bool backtrack(vector<vector<char>>& board) {
if (empties.empty()) return true;
sort(empties.begin(), empties.end(), [&](const pair<int,int>& a, const pair<int,int>& b) {
return getCandidates(a.first, a.second).size() < getCandidates(b.first, b.second).size();
});
auto pos = empties.front();
empties.erase(empties.begin());
int r = pos.first, c = pos.second;
int b = (r/3)*3 + c/3;
for (char ch : getCandidates(r, c)) {
board[r][c] = ch;
rows[r].insert(ch);
cols[c].insert(ch);
boxes[b].insert(ch);
if (backtrack(board)) return true;
board[r][c] = '.';
rows[r].erase(ch);
cols[c].erase(ch);
boxes[b].erase(ch);
}
empties.insert(empties.begin(), pos);
return false;
}
};
int main() {
vector<vector<char>> 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'}
};
Solution sol;
sol.solveSudoku(board);
for (auto& row : board) {
for (auto& c : row) cout << c << ' ';
cout << '\n';
}
return 0;
}
Line Notes
vector<char> getCandidates(int r, int c)Returns valid digits for cell (r,c)
sort(empties.begin(), empties.end(), [&](const pair<int,int>& a, const pair<int,int>& b)Sort empties by fewest candidates
auto pos = empties.front();Choose most constrained cell
empties.erase(empties.begin());Remove chosen cell from empties
for (char ch : getCandidates(r, c))Try all valid digits
empties.insert(empties.begin(), pos);Backtrack by reinserting cell
rows[r].insert(ch);Mark digit used in row
board[r][c] = '.';Reset cell on backtrack
var solveSudoku = function(board) {
const rows = Array.from({length:9}, () => new Set());
const cols = Array.from({length:9}, () => new Set());
const boxes = Array.from({length:9}, () => new Set());
const empties = [];
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const c = board[i][j];
if (c === '.') {
empties.push([i, j]);
} else {
rows[i].add(c);
cols[j].add(c);
boxes[Math.floor(i/3)*3 + Math.floor(j/3)].add(c);
}
}
}
function getCandidates(r, c) {
const b = Math.floor(r/3)*3 + Math.floor(c/3);
const candidates = [];
for (let ch = 1; ch <= 9; ch++) {
const val = ch.toString();
if (!rows[r].has(val) && !cols[c].has(val) && !boxes[b].has(val)) {
candidates.push(val);
}
}
return candidates;
}
function backtrack() {
if (empties.length === 0) return true;
empties.sort((a,b) => getCandidates(a[0], a[1]).length - getCandidates(b[0], b[1]).length);
const [r, c] = empties.shift();
const b = Math.floor(r/3)*3 + Math.floor(c/3);
for (const ch of getCandidates(r, c)) {
board[r][c] = ch;
rows[r].add(ch);
cols[c].add(ch);
boxes[b].add(ch);
if (backtrack()) return true;
board[r][c] = '.';
rows[r].delete(ch);
cols[c].delete(ch);
boxes[b].delete(ch);
}
empties.unshift([r, c]);
return false;
}
backtrack();
};
// Example usage:
let 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']
];
solveSudoku(board);
console.log(board.map(row => row.join(' ')).join('\n'));
Line Notes
function getCandidates(r, c)Returns valid digits for cell (r,c)
empties.sort((a,b) => getCandidates(a[0], a[1]).length - getCandidates(b[0], b[1]).length);Sort empties by fewest candidates
const [r, c] = empties.shift();Choose most constrained cell
for (const ch of getCandidates(r, c))Try all valid digits
empties.unshift([r, c]);Backtrack by reinserting cell
rows[r].add(ch);Mark digit used in row
board[r][c] = '.';Reset cell on backtrack