diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java index 543fe2d02b50..5ad4bfa6046b 100644 --- a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java +++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java @@ -1,157 +1,100 @@ package com.thealgorithms.backtracking; /** - * Sudoku Solver using Backtracking Algorithm - * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9) + * The {@code SudokuSolver} class provides a solution to Sudoku puzzles. + * Solves the puzzle by a depth-first backtracking algorithm. * - * @author Navadeep0007 + *

The algorithm fills empty cells (represented by 0) by trying digits 1-9 and + * recursively verifying if they lead to a valid solution. + * + *

Time Complexity: O(9^{n*n}) where n is the dimension of the grid. + * Space Complexity: O(n*n) to store the board and recursion stack. + * + * @author subhammohanty-sys */ public final class SudokuSolver { - private static final int GRID_SIZE = 9; - private static final int SUBGRID_SIZE = 3; - private static final int EMPTY_CELL = 0; - private SudokuSolver() { - // Utility class, prevent instantiation } /** - * Solves the Sudoku puzzle using backtracking + * Entry point to solve the Sudoku puzzle. Performs a pre-validation check + * before starting the recursion. * - * @param board 9x9 Sudoku board with 0 representing empty cells - * @return true if puzzle is solved, false otherwise + * @param board 2D array representing the Sudoku grid (0 for empty cells). + * @return true if the board is solvable, false otherwise. */ public static boolean solveSudoku(int[][] board) { - if (board == null || board.length != GRID_SIZE) { + if (board == null || board.length != 9) { return false; } - for (int row = 0; row < GRID_SIZE; row++) { - if (board[row].length != GRID_SIZE) { + for (int[] row : board) { + if (row == null || row.length != 9) { return false; } } + if (!isBoardValid(board)) { + return false; + } + return solve(board); } - /** - * Recursive helper method to solve the Sudoku puzzle - * - * @param board the Sudoku board - * @return true if solution is found, false otherwise - */ - private static boolean solve(int[][] board) { - for (int row = 0; row < GRID_SIZE; row++) { - for (int col = 0; col < GRID_SIZE; col++) { - if (board[row][col] == EMPTY_CELL) { - for (int number = 1; number <= GRID_SIZE; number++) { - if (isValidPlacement(board, row, col, number)) { - board[row][col] = number; - - if (solve(board)) { - return true; - } - - // Backtrack - board[row][col] = EMPTY_CELL; - } + private static boolean isBoardValid(int[][] board) { + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != 0) { + int num = board[i][j]; + board[i][j] = 0; + if (!isValid(board, i, j, num)) { + return false; } - return false; + board[i][j] = num; } } } return true; } - /** - * Checks if placing a number at given position is valid - * - * @param board the Sudoku board - * @param row row index - * @param col column index - * @param number number to place (1-9) - * @return true if placement is valid, false otherwise - */ - private static boolean isValidPlacement(int[][] board, int row, int col, int number) { - return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number); - } - - /** - * Checks if number exists in the given row - * - * @param board the Sudoku board - * @param row row index - * @param number number to check - * @return true if number exists in row, false otherwise - */ - private static boolean isNumberInRow(int[][] board, int row, int number) { - for (int col = 0; col < GRID_SIZE; col++) { - if (board[row][col] == number) { - return true; - } - } - return false; - } - - /** - * Checks if number exists in the given column - * - * @param board the Sudoku board - * @param col column index - * @param number number to check - * @return true if number exists in column, false otherwise - */ - private static boolean isNumberInColumn(int[][] board, int col, int number) { - for (int row = 0; row < GRID_SIZE; row++) { - if (board[row][col] == number) { - return true; + private static boolean isValid(int[][] board, int row, int col, int num) { + for (int i = 0; i < 9; i++) { + if (board[i][col] == num || board[row][i] == num) { + return false; } } - return false; - } - /** - * Checks if number exists in the 3x3 subgrid - * - * @param board the Sudoku board - * @param row row index - * @param col column index - * @param number number to check - * @return true if number exists in subgrid, false otherwise - */ - private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) { - int subgridRowStart = row - row % SUBGRID_SIZE; - int subgridColStart = col - col % SUBGRID_SIZE; + int sr = row / 3 * 3; + int sc = col / 3 * 3; - for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) { - for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) { - if (board[i][j] == number) { - return true; + for (int i = sr; i < sr + 3; i++) { + for (int j = sc; j < sc + 3; j++) { + if (board[i][j] == num) { + return false; } } } - return false; + return true; } - /** - * Prints the Sudoku board - * - * @param board the Sudoku board - */ - public static void printBoard(int[][] board) { - for (int row = 0; row < GRID_SIZE; row++) { - if (row % SUBGRID_SIZE == 0 && row != 0) { - System.out.println("-----------"); - } - for (int col = 0; col < GRID_SIZE; col++) { - if (col % SUBGRID_SIZE == 0 && col != 0) { - System.out.print("|"); + private static boolean solve(int[][] board) { + for (int row = 0; row < 9; row++) { + for (int col = 0; col < 9; col++) { + if (board[row][col] == 0) { + for (int num = 1; num <= 9; num++) { + if (isValid(board, row, col, num)) { + board[row][col] = num; + if (solve(board)) { + return true; + } + board[row][col] = 0; + } + } + return false; } - System.out.print(board[row][col]); } - System.out.println(); } + return true; } } diff --git a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java index 3d31cb3e7f6c..4c17a2b65873 100644 --- a/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java +++ b/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java @@ -1,10 +1,3 @@ -/** - * [Brief description of what the algorithm does] - *

- * Time Complexity: O(n) [or appropriate complexity] - * Space Complexity: O(n) - * @author Reshma Kakkirala - */ package com.thealgorithms.conversions; import java.util.Arrays; @@ -13,6 +6,12 @@ import java.util.Scanner; /** + * [Brief description of what the algorithm does] + *

+ * Time Complexity: O(n) [or appropriate complexity] Space Complexity: O(n) + * + * @author Reshma Kakkirala + * * Class for converting from "any" base to "any" other base, when "any" means * from 2-36. Works by going from base 1 to decimal to base 2. Includes * auxiliary method for determining whether a number is valid for a given base. @@ -21,6 +20,7 @@ * @version 2017.10.10 */ public final class AnyBaseToAnyBase { + private AnyBaseToAnyBase() { } @@ -70,44 +70,7 @@ public static void main(String[] args) { * Checks if a number (as a String) is valid for a given base. */ public static boolean validForBase(String n, int base) { - char[] validDigits = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F', - 'G', - 'H', - 'I', - 'J', - 'K', - 'L', - 'M', - 'N', - 'O', - 'P', - 'Q', - 'R', - 'S', - 'T', - 'U', - 'V', - 'W', - 'X', - 'Y', - 'Z', - }; + char[] validDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; // digitsForBase contains all the valid digits for the base given char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base); diff --git a/src/main/java/com/thealgorithms/searches/InterpolationSearch.java b/src/main/java/com/thealgorithms/searches/InterpolationSearch.java index d24cc1c774bc..8eaee2842559 100644 --- a/src/main/java/com/thealgorithms/searches/InterpolationSearch.java +++ b/src/main/java/com/thealgorithms/searches/InterpolationSearch.java @@ -1,26 +1,22 @@ -/** - * Interpolation Search estimates the position of the target value - * based on the distribution of values. - * - * Example: - * Input: [10, 20, 30, 40], target = 30 - * Output: Index = 2 - * - * Time Complexity: O(log log n) (average case) - * Space Complexity: O(1) - */ package com.thealgorithms.searches; /** - * InterpolationSearch is an algorithm that searches for a target value within a sorted array - * by estimating the position based on the values at the corners of the current search range. + * Interpolation Search estimates the position of the target value based on the + * distribution of values. + * + * Example: Input: [10, 20, 30, 40], target = 30 Output: Index = 2 + * + * Time Complexity: O(log log n) (average case) Space Complexity: O(1) + * + * InterpolationSearch is an algorithm that searches for a target value within a + * sorted array by estimating the position based on the values at the corners of + * the current search range. * *

- * The performance of this algorithm can vary: - * - Worst-case performance: O(n) - * - Best-case performance: O(1) - * - Average performance: O(log(log(n))) if the elements are uniformly distributed; otherwise O(n) - * - Worst-case space complexity: O(1) + * The performance of this algorithm can vary: - Worst-case performance: O(n) - + * Best-case performance: O(1) - Average performance: O(log(log(n))) if the + * elements are uniformly distributed; otherwise O(n) - Worst-case space + * complexity: O(1) *

* *

@@ -32,7 +28,8 @@ class InterpolationSearch { /** - * Finds the index of the specified key in a sorted array using interpolation search. + * Finds the index of the specified key in a sorted array using + * interpolation search. * * @param array The sorted array to search. * @param key The value to search for. diff --git a/src/main/java/com/thealgorithms/searches/LinearSearch.java b/src/main/java/com/thealgorithms/searches/LinearSearch.java index 3f273e167f0a..8a67e1157e7d 100644 --- a/src/main/java/com/thealgorithms/searches/LinearSearch.java +++ b/src/main/java/com/thealgorithms/searches/LinearSearch.java @@ -1,31 +1,23 @@ -/** - * Performs Linear Search on an array. - * - * Linear search checks each element one by one until the target is found - * or the array ends. - * - * Example: - * Input: [2, 4, 6, 8], target = 6 - * Output: Index = 2 - * - * Time Complexity: O(n) - * Space Complexity: O(1) - */ package com.thealgorithms.searches; import com.thealgorithms.devutils.searches.SearchAlgorithm; /** - * Linear Search is a simple searching algorithm that checks - * each element of the array sequentially until the target - * value is found or the array ends. + * Performs Linear Search on an array. + * + * Linear search checks each element one by one until the target is found or the + * array ends. + * + * Example: Input: [2, 4, 6, 8], target = 6 Output: Index = 2 + * + * Time Complexity: O(n) Space Complexity: O(1) + * + * Linear Search is a simple searching algorithm that checks each element of the + * array sequentially until the target value is found or the array ends. * * It works for both sorted and unsorted arrays. * - * Time Complexity: - * - Best case: O(1) - * - Average case: O(n) - * - Worst case: O(n) + * Time Complexity: - Best case: O(1) - Average case: O(n) - Worst case: O(n) * * Space Complexity: O(1) * @@ -41,7 +33,8 @@ public class LinearSearch implements SearchAlgorithm { * * @param array List to be searched * @param value Key being searched for - * @return Location of the key, -1 if array is null or empty, or key not found + * @return Location of the key, -1 if array is null or empty, or key not + * found */ @Override public > int find(T[] array, T value) { diff --git a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java index 75d3eae08629..202341726e09 100644 --- a/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java +++ b/src/test/java/com/thealgorithms/backtracking/SudokuSolverTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; - import org.junit.jupiter.api.Test; class SudokuSolverTest { @@ -46,8 +45,29 @@ void testSolveSudokuNullBoard() { @Test void testSolveSudokuEmptyBoard() { - int[][] board = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0}}; - + int[][] board = new int[9][9]; assertTrue(SudokuSolver.solveSudoku(board)); } + + @Test + void testSolveInitiallyInvalidBoard() { + int[][] board = new int[9][9]; + board[0][0] = 5; + board[0][1] = 5; + assertFalse(SudokuSolver.solveSudoku(board)); + } + + @Test + void testSolveSudokuUnsolvablePuzzle() { + int[][] board = {{5, 1, 6, 8, 4, 9, 7, 3, 2}, {3, 0, 7, 6, 0, 5, 0, 0, 0}, {8, 0, 9, 1, 0, 0, 0, 6, 0}, {1, 3, 0, 4, 0, 7, 0, 0, 0}, {0, 0, 2, 0, 1, 0, 3, 0, 0}, {0, 0, 0, 9, 0, 3, 0, 1, 7}, {0, 6, 0, 0, 0, 1, 9, 0, 3}, {0, 0, 0, 3, 0, 8, 5, 0, 1}, {0, 0, 0, 5, 0, 0, 4, 7, 0}}; + board[1][1] = 5; + assertFalse(SudokuSolver.solveSudoku(board)); + } + + @Test + void testIrregularBoardRowLength() { + int[][] irregularBoard = {{0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}}; + + assertFalse(SudokuSolver.solveSudoku(irregularBoard)); + } }