diff --git a/Problem1.py b/Problem1.py new file mode 100644 index 00000000..da2de6c1 --- /dev/null +++ b/Problem1.py @@ -0,0 +1,102 @@ +## Problem1 +# N Queens(https://leetcode.com/problems/n-queens/) + + +# N -- No. of Rows and No. of Cols +# Time Complexity : O(N * N!) = O((N + 1)!) = O(N!) +# For each row we have N * (N - 2) * (N - 4) * (N - 6) = N factorial = N! options +# For each cell we check isSafe function. TC for isSafe function = O(N) -- Linear +# TC for is safe function --- O(2 * N) * All possible combinations +# So O(N) --- to check queen in same column above +# O(N) --- Right diagonal up + Left Diagonal Up + +# Space Complexity : O(N^2) -- storing the grid +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No + + +# Your code here along with comments explaining your approach in three sentences only +# We exhaustively explore all possible combinations to place the queen. We know only one queen can come in a single row. So exhautively +# for each row we go through all the cells(columns) and check if it is safe to put a queen there. If it is safe we put the queen at that cell +# and recurse to the next row. When we have completed all the rows, it means all the queens have been placed. Then we make our valid matrix +# as required in the question and append to the result. The isSafe function checks if the queen can be placed at the given cell or not. There +# are 3 cases to check -- same column all the above rows from the current row, diagonaly right up and diagonally left up. + +class Solution(object): + def solveNQueens(self, n): + """ + :type n: int + :rtype: List[List[str]] + """ + # check if we can place the queen at cell (i, j) safely + def isQueenSafe(rowNo, colNo, board): + # check same column above + for i in range(rowNo): + if(board[i][colNo] == "Q"): + return False + + # check diagonal up left + r = rowNo - 1 + c = colNo - 1 + while((r >= 0) and (c >= 0)): + if(board[r][c] == "Q"): + return False + r -= 1 + c -= 1 + + # check diagonal up right + r = rowNo - 1 + c = colNo + 1 + while((r >= 0) and (c < len(board[r]))): + if(board[r][c] == "Q"): + return False + r -= 1 + c += 1 + + return True + + # exhaustive function to place the queens + def helper(board, rowNo, allPossRes): + # base case + if(rowNo == len(board)): + # we have placed all the queens successfully + newRes = [] + for m in range(len(board)): #O(N) -- rows + newRes.append("".join(board[m])) # O(N) for each join + + allPossRes.append(newRes) + return + + # logic + # for a row checking each cell(column) if we can place the queen + for k in range(len(board)): + if(isQueenSafe(rowNo, k, board)): + # yes it is safe + + # action + board[rowNo][k] = "Q" + # so recurse in the next row + helper(board, rowNo + 1, allPossRes) + # backtrack + board[rowNo][k] = "." + + # create the chess board + board = [] + for i in range(n): + row = [] + for j in range(n): + row.append(".") + + board.append(row) + + allPossRes = [] + helper(board, 0, allPossRes) + return allPossRes + + +sol = Solution() +print(sol.solveNQueens(1)) +print(sol.solveNQueens(2)) +print(sol.solveNQueens(3)) +print(sol.solveNQueens(4)) +print(sol.solveNQueens(5)) \ No newline at end of file diff --git a/Problem2.py b/Problem2.py new file mode 100644 index 00000000..3e7686d1 --- /dev/null +++ b/Problem2.py @@ -0,0 +1,166 @@ +## Problem2 +# Word Search(https://leetcode.com/problems/word-search/) + +# Method-1: Using void based recursion +# M -- No. of Rows +# N -- No. of Cols +# L -- Length of the word +# Time Complexity : O((M*N) * (3 ^ (L))) +# TC: 3 ^ (L) --- for one DFS and we can have total M*N DFS + +# Space Complexity : O(L) = O(L) -- recursive stack +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No + +# Your code here along with comments explaining your approach in three sentences only +# Wherever we match the first letter of the word to be searched in the grid, we start a fresh DFS. We have to keep track of our current path +# that is visited cells as reusing a used cell is not allowed. So when the recursion returns we need to backtrack the action of making the +# cell visited, so that we can explore other paths from there. As other path could give us the word we are searching. For visited we are +# temporarily changing the state of the matrix to #. At each node we have 3 options to explore as we go deep into the tree. Max depth +# of this tree would be the length of the word we are seaching. Here the input matrix remains preserved + +class Solution(object): + def __init__(self): + self.isWordFound = False + def exist(self, board, word): + """ + :type board: List[List[str]] + :type word: str + :rtype: bool + """ + if(len(word) > (len(board) * len(board[0]))): + # word length > matrix length + return False + + def helper(board, word, strIdx, row, col, dirs): + # base + # first check if word has been found. this condition should come first + if(strIdx == len(word)): + # word found + self.isWordFound = True + return + + # bounds and visited check + if((row < 0) or (row >= len(board)) or (col < 0) or (col >= len(board[row])) or (board[row][col] == "#")): + return + + if(self.isWordFound): + # word already found + return + + if(board[row][col] == word[strIdx]): + # then only proceed further + # action + board[row][col] = "#" + # till now word is matching, lets recurse further + for k in range(len(dirs)): + nr = row + dirs[k][0] + nc = col + dirs[k][1] + # recurse + helper(board, word, strIdx + 1, nr, nc, dirs) + # if(self.isWordFound): + # # word already found + # return + + # backtrack + board[row][col] = word[strIdx] + + m = len(board) + n = len(board[0]) + dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] + self.isWordFound = False + for i in range(m): + for j in range(n): + if(board[i][j] == word[0]): + # start a fresh DFS + + helper(board, word, 0, i, j, dirs) + if(self.isWordFound): + # word already found + return True + + + return False + +sol = Solution() +print("Method-1: Using void based recursion") +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCCED")) +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "SEE")) +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCB")) +print(sol.exist([["A","E","E","D"],["S","F","C","S"],["A","D","E","E"]], "SFCEESDEE")) + +# Method-2: Using boolean based recursion +# M -- No. of Rows +# N -- No. of Cols +# L -- Length of the word +# Time Complexity : O((M*N) * (3 ^ (L))) +# TC: 3 ^ (L) --- for one DFS and we can have total M*N DFS + +# Space Complexity : O(L) = O(L) -- recursive stack +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No + +# Your code here along with comments explaining your approach in three sentences only +# The logic is exactly same. Just here we are using boolean based recursion. Here the input matrix changes as all the actions might not get +# backtracked + +class Solution(object): + def exist(self, board, word): + """ + :type board: List[List[str]] + :type word: str + :rtype: bool + """ + if(len(word) > (len(board) * len(board[0]))): + # word length > matrix length + return False + + def helper(board, word, strIdx, row, col, dirs): + # base + # first check if word has been found. this condition should come first + if(strIdx == len(word)): + # word found + return True + + # bounds and visited check + if((row < 0) or (row >= len(board)) or (col < 0) or (col >= len(board[row])) or (board[row][col] == "#")): + return False + + if(board[row][col] == word[strIdx]): + # then only proceed further + # action + board[row][col] = "#" + # till now word is matching, lets recurse further + for k in range(len(dirs)): + nr = row + dirs[k][0] + nc = col + dirs[k][1] + # recurse + if(helper(board, word, strIdx + 1, nr, nc, dirs)): + return True + + # backtrack + board[row][col] = word[strIdx] + + return False + + m = len(board) + n = len(board[0]) + dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] + for i in range(m): + for j in range(n): + if(board[i][j] == word[0]): + # start a fresh DFS + + if(helper(board, word, 0, i, j, dirs)): + return True + + return False + +sol = Solution() +print("Method-2: Using boolean based recursion") +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCCED")) +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "SEE")) +print(sol.exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCB")) +print(sol.exist([["A","E","E","D"],["S","F","C","S"],["A","D","E","E"]], "SFCEESDEE")) + +