diff --git a/src/NQueens.java b/src/NQueens.java new file mode 100644 index 00000000..b831e520 --- /dev/null +++ b/src/NQueens.java @@ -0,0 +1,109 @@ +import java.util.ArrayList; +import java.util.List; + +public class NQueens { + + private List> solutions; + + /* + * Time Complexity: + * - Each placement calls isValid() which scans up to O(n) vertically and diagonally -> O(n) + * - Rough upper bound: O(n! * n) + * Space Complexity: + * - O(n^2) for the board + O(n) recursion depth + */ + public List> solveNQueens(int n) { + solutions = new ArrayList<>(); + boolean[][] board = new boolean[n][n]; // true means a queen is placed + backtrack(board, 0, n); + return solutions; + } + + /* + Place a queen in one row and recursively slow the other rows + */ + private void backtrack(boolean[][] board, int row, int n) { + // Base case: if we've placed queens in all rows, we found a valid solution + if (row == n) { + solutions.add(buildSolution(board, n)); + return; + } + + // Try placing a queen in every column of the current row + for (int col = 0; col < n; col++) { + if (isValid(board, row, col, n)) { + // Choose + board[row][col] = true; + + // Explore + backtrack(board, row + 1, n); + + // Un-choose (backtrack) + board[row][col] = false; + } + } + } + + /* + Converts the boolean board into the required List representation + */ + private List buildSolution(boolean[][] board, int n) { + List list = new ArrayList<>(); + for (int i = 0; i < n; i++) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < n; j++) { + sb.append(board[i][j] ? 'Q' : '.'); + } + list.add(sb.toString()); + } + return list; + } + + /* + * Checks if placing a queen at (row, col) is safe. + * Since we place queens row-by-row from top to bottom, we only need to check: + * 1) same column above + * 2) upper-left diagonal + * 3) upper-right diagonal + */ + private boolean isValid(boolean[][] board, int row, int col, int n) { + //Check same column (above rows) + for (int r = row; r >= 0; r--) { + if (board[r][col]) return false; + } + + // Check upper-left diagonal + for (int r = row, c = col; r >= 0 && c >= 0; r--, c--) { + if (board[r][c]) return false; + } + + // Check upper-right diagonal + for (int r = row, c = col; r >= 0 && c < n; r--, c++) { + if (board[r][c]) return false; + } + + return true; + } + + // Test + public static void main(String[] args) { + NQueens solver = new NQueens(); + + int n = 4; + List> res = solver.solveNQueens(n); + + System.out.println("n = " + n); + System.out.println("Number of solutions: " + res.size()); + System.out.println(); + + // Print all solutions + int solNum = 1; + for (List sol : res) { + System.out.println("Solution " + solNum++ + ":"); + for (String row : sol) { + System.out.println(row); + } + System.out.println(); + } + } +} diff --git a/src/WordSearch.java b/src/WordSearch.java new file mode 100644 index 00000000..196e97c4 --- /dev/null +++ b/src/WordSearch.java @@ -0,0 +1,81 @@ +public class WordSearch { + // Directions: up, down, right, left + private int[][] dirs; + private int m, n; + /* + Time Complexity - O(m * n * 4^L) where L = word.length() + Space Complexity - O(L) recursion stack in the worst case. + */ + public boolean exist(char[][] board, String word) { + this.dirs = new int[][]{{-1, 0}, {1, 0}, {0, 1}, {0, -1}}; + this.m = board.length; + this.n = board[0].length; + + // Try starting the DFS from every cell in the board + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // if DFS succeeds, return true immediately + if (dfs(board, i, j, word, 0)) { + return true; + } + } + } + return false; + } + + /** + * DFS (backtracking) to match word[idx...] starting from board[i][j]. + */ + private boolean dfs(char[][] board, int i, int j, String word, int idx) { + // Base case: we've matched all characters + if (idx == word.length()) return true; + + // Out of bounds or already visited + if (i < 0 || j < 0 || i == m || j == n || board[i][j] == '#') return false; + + // Current cell must match the current character in word + if (board[i][j] != word.charAt(idx)) return false; + + // Mark as visited (so we don't reuse the same cell in this path) + char saved = board[i][j]; + board[i][j] = '#'; + + // Explore 4 neighbors + for (int[] dir : dirs) { + int x = i + dir[0]; + int y = j + dir[1]; + + if (dfs(board, x, y, word, idx + 1)) { + // Restore before returning + board[i][j] = saved; + return true; + } + } + + // Backtrack: restore the original value before returning + board[i][j] = saved; + return false; + } + + // Testing + public static void main(String[] args) { + WordSearch ws = new WordSearch(); + + char[][] board1 = { + {'A','B','C','E'}, + {'S','F','C','S'}, + {'A','D','E','E'} + }; + + System.out.println(ws.exist(board1, "ABCCED")); // true + System.out.println(ws.exist(board1, "SEE")); // true + System.out.println(ws.exist(board1, "ABCB")); // false + + char[][] board2 = { + {'C','A','A'}, + {'A','A','A'}, + {'B','C','D'} + }; + System.out.println(ws.exist(board2, "AAB")); // true + } +}