Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions Problem1.py
Original file line number Diff line number Diff line change
@@ -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))
166 changes: 166 additions & 0 deletions Problem2.py
Original file line number Diff line number Diff line change
@@ -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"))