Related
I'm a beginner in Leetcode & Python and I tried to solve the N-Queen Problem. Below is the solution in Python which passed submission
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def isSafe(row, x_col):
# check row
for x in range(n):
if placed[row][x] is True and x != x_col:
return False
# check column
for x in range(n):
if placed[x][x_col] is True and x != row:
return False
# check diagnol
i, j = row, x_col
while i > 0 and j < n - 1:
if placed[i - 1][j + 1] is True:
return False
i -= 1
j += 1
i, j = row, x_col
while i < n - 1 and j < 0:
if placed[i + 1][j - 1] is True:
return False
i -= 1
j += 1
# #check offdiagnol
i, j = row, x_col
while i > 0 and j > 0:
if placed[i - 1][j - 1] is True:
return False
i -= 1
j -= 1
i, j = row, x_col
while i < n-1 and j < n-1:
if placed[i][j] is True:
return False
i += 1
j += 1
return True
def process(currconfig, matrix, n, row):
#base condition
if row == n:
curr = []
for x in range(n):
curr.append(currconfig[x])
totalconfig.append(currconfig)
return
for x_col in range(n):
if isSafe(row, x_col):
path = x_col * '.' + 'Q' + (n - x_col - 1) * '.'
currconfig.append(path)
matrix[row][x_col] = True
#process recursively called
process(currconfig, matrix, n, row + 1)
currconfig.pop()
matrix[row][x_col] = False
configuration = []
totalconfig = []
placed = [[False for _ in range(n)] for _ in range(n)]
process(configuration, placed, n, 0)
return totalconfig
a = Solution()
print(a.solveNQueens(4))
I only have a doubt about the base condition of the process function. In the process function's base condition I initially did this and got empty Lists appended to totalconfig no matter what, CASE I:
def process(currconfig, matrix, n, row):
if row == n:
totalconfig.append(currconfig)
return
so spent a few hours trying to get around the problem and weirdly enough for me this worked, CASE II :
def process(currconfig, matrix, n, row):
if row == n:
curr = []
for x in range(n):
curr.append(currconfig[x])
totalconfig.append(currconfig)
return
I don't get why the CASE I did not work but CASE II worked. What am I missing...How is "currconfig" in CASE I different from "curr" in CASE II
it looks like you are not using functions (methods) in classes correctly.
Basically, the first argument is the self which refers to itself. In your case, currconfig is self.
So presumably the function should have looked like this:
def process(self, currconfig, matrix, n, row): # <---added self
if row == n:
totalconfig.append(currconfig)
return
I need to find the biggest sequence of zeros next to each other (up down left right).
for example in this example the function should return 6
mat = [[1,**0**,**0**,3,0],
[**0**,**0**,2,3,0],
[2,**0**,**0**,2,0],
[0,1,2,3,3],]
the zeros that i marked as bold should be the answer (6)
the solution should be implemented without any loop (using recursion)
this is what i tried so far
def question_3_b(some_list,index_cord):
y = index_cord[0]
x = index_cord[1]
list_of_nums = []
def main(some_list,index_cord):
y = index_cord[0]
x = index_cord[1]
def check_right(x,y):
if x + 1 < 0:
return 0
if some_list[y][x+1] == 0:
main(some_list,(y,x+1))
else:
return 0
def check_left(x,y):
if x -1 < 0:
return 0
if some_list[y][x - 1] == 0:
main(some_list,(y, x - 1))
def check_down(x,y):
if y + 1 < 0:
return 0
try:
if some_list[y + 1][x] == 0:
main(some_list,(y + 1, x))
except:
print("out of range")
def check_up(x,y):
counter_up = 0
if y - 1 < 0:
return 0
if some_list[y - 1][x] == 0:
counter_up += 1
main(some_list,(y - 1, x))
list_of_nums.append((x,y))
right = check_right(x,y)
down = check_down(x,y)
left = check_left(x,y)
up = check_up(x, y)
main(some_list,index_cord)
print(list_of_nums)
question_3_b(mat,(0,1))
Solution #1: classic BFS
As I mention in a comment, you can tackle this problem using BFS (Breadth First Search), it will be something like this:
# This function will give the valid adjacent positions
# of a given position according the matrix size (NxM)
def valid_adj(i, j, N, M):
adjs = [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]]
for a_i, a_j in adjs:
if 0 <= a_i < N and 0 <= a_j < M:
yield a_i, a_j
def biggest_zero_chunk(mat):
answer = 0
N, M = len(mat), len(mat[0])
# Mark all non zero position as visited (we are not instrested in them)
mask = [[mat[i][j] != 0 for j in range(M)] for i in range(N)]
queue = []
for i in range(N):
for j in range(M):
if mask[i][j]: # You have visited this position
continue
# Here comes the BFS
# It visits all the adjacent zeros recursively,
# count them and mark them as visited
current_ans = 1
queue = [[i,j]]
while queue:
pos_i, pos_j = queue.pop(0)
mask[pos_i][pos_j] = True
for a_i, a_j in valid_adj(pos_i, pos_j, N, M):
if mat[a_i][a_j] == 0 and not mask[a_i][a_j]:
queue.append([a_i, a_j])
current_ans += 1
answer = max(answer, current_ans)
return answer
mat = [[1,0,0,3,0],
[0,0,2,3,0],
[2,0,0,2,0],
[0,1,2,3,3],]
mat2 = [[1,0,0,3,0],
[0,0,2,3,0],
[2,0,0,0,0], # A slight modification in this row to connect two chunks
[0,1,2,3,3],]
print(biggest_zero_chunk(mat))
print(biggest_zero_chunk(mat2))
Output:
6
10
Solution #2: using only recursion (no for statements)
def count_zeros(mat, i, j, N, M):
# Base case
# Don't search zero chunks if invalid position or non zero values
if i < 0 or i >= N or j < 0 or j >= M or mat[i][j] != 0:
return 0
ans = 1 # To count the current zero we start at 1
mat[i][j] = 1 # To erase the current zero and don't count it again
ans += count_zeros(mat, i - 1, j, N, M) # Up
ans += count_zeros(mat, i + 1, j, N, M) # Down
ans += count_zeros(mat, i, j - 1, N, M) # Left
ans += count_zeros(mat, i, j + 1, N, M) # Right
return ans
def biggest_zero_chunk(mat, i = 0, j = 0, current_ans = 0):
N, M = len(mat), len(mat[0])
# Base case (last position of mat)
if i == N - 1 and j == M - 1:
return current_ans
next_j = (j + 1) % M # Move to next column, 0 if j is the last one
next_i = i + 1 if next_j == 0 else i # Move to next row if j is 0
ans = count_zeros(mat, i, j, N, M) # Count zeros from this position
current_ans = max(ans, current_ans) # Update the current answer
return biggest_zero_chunk(mat, next_i, next_j, current_ans) # Check the rest of mat
mat = [[1,0,0,3,0],
[0,0,2,3,0],
[2,0,0,2,0],
[0,1,2,3,3],]
mat2 = [[1,0,0,3,0],
[0,0,2,3,0],
[2,0,0,0,0], # A slight modification in this row to connect two chunks
[0,1,2,3,3],]
print(biggest_zero_chunk(mat.copy()))
print(biggest_zero_chunk(mat2.copy()))
Output:
6
10
Notes:
The idea behind this solution is still BFS (represented mainly in the count_zeros function). Also, if you are interested in using the matrix values after this you should call the biggest_zero_chunk with a copy of the matrix (because it is modified in the algorithm)
Description of the problem is below:
Given the matrix of M rows and N columns, 0 represents empty space,- 1 represents obstacle, and 1 represents target points (there are multiple target points).
For each empty space, if you want to reach a target point at the shortest distance, please mark the direction of the first step.
If starting up, you should mark the point as 2. if starting down , you should mark the point as 3. if starting left , you should mark the point as 4. if starting right , you should mark the point as 5.
The priority of direction is up, down, left and right from big to small, that is, if you can reach the target point with the shortest distance from a point up or down, you are supposed to start up.
Returns the matrix after marking. 0< m, n< 1000
I tried to wrote solution in python, but always get 'TypeError: 'NoneType' object is not iterable'. Really don't know why. I would really appreciate your help if you can point out the problem!
My basic idea is, for each empty cell, find its nearest target using BFS. then by specifying this empty cell as start and this nearest target as destination, i find out the direction of the first step. Code might not be so concise, thanks for your time and effort!
class Solution:
"""
#param grid: the input matrix
#return: the new matrix
"""
grid = None
def shortestPath(self, grid):
# BFS
self.grid = grid.copy()
m = len(grid)
n = len(grid[0]) if m > 0 else 0
res = [[None] * n for _ in range(m)]
for i in range(m):
for j in range(n):
if grid[i][j] not in [-1, 1]:
tarx, tary, step = self.bfs(i, j)
res[i][j] = self.search(i, j, tarx, tary)
else:
res[i][j] = grid[i][j]
return res
def search(self, i, j, tarx, tary):
dic = {0: 2, 1: 3, 2: 4, 3: 5}
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
min_dist = float('inf')
direction = -1
for idx, d in enumerate(dirs):
x, y = i + d[0], j + d[1]
if x == tarx and y == tary:
return dic[idx]
if self.inside(x, y):
arr = [tarx, tary]
_, __, dist = self.bfs(x, y, arr)
if min_dist > dist:
min_dist = dist
direction = dic[idx]
return direction
def bfs(self, i, j, target = None):
m = len(self.grid)
n = len(self.grid[0]) if m > 0 else 0
visit = [[False] * n for _ in range(m)]
visit[i][j] = True
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
qu = [(i, j, 0)]
while len(qu) > 0:
ti, tj, step = qu[0][0], qu[0][1], qu[0][2]
qu.pop()
for d in dirs:
x, y = ti + d[0], tj + d[1]
if self.inside(x, y) and not visit[x][y]:
if not target:
if self.grid[x][y] == 1:
return x, y, step + 1
else:
tarx, tary = target[0], target[1]
if x == tarx and y == tary:
return x, y, step + 1
visit[x][y] = True
qu.append((x, y, step + 1))
def inside(self, x, y):
if 0 <= x < len(self.grid) and 0 <= y < len(self.grid[0]) and self.grid[x][y] != -1:
return True
return False
if __name__ == '__main__':
testcase = [[1,0,0],[0,0,0]]
ans = Solution().shortestPath(testcase)
print(ans)
bfs does not return a triple from all possible execution paths. If you finish the loop without finding a solution, then you drop out the bottom and return None. This makes your unpacking assignment fail.
Please see debug for your future use; we expect you to do the initial problem diagnosis, not merely dump an untracked program on us.
Problem Description:
You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:
Each 0 marks an empty land which you can pass by freely.
Each 1 marks a building which you cannot pass through.
Each 2 marks an obstacle which you cannot pass through.
For example, given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2):
1 - 0 - 2 - 0 - 1
| | | | |
0 - 0 - 0 - 0 - 0
| | | | |
0 - 0 - 1 - 0 - 0
The point (1,2) is an ideal empty land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7.
I solved this problem by BFS way. Then I want to solve it with DFS way but got stuck. Below is my code:
class Solution(object):
def shortestDistance(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
rl, cl = len(grid), len(grid[0])
builds = sum([col for row in grid for col in row if col == 1])
dist, hit = [[0] * cl for _ in range(rl)], [[0] * cl for _ in range(rl)]
def dfs(x, y, step):
'''
Wrong answer, it seems result dist alway keep the longest distance?
'''
if 0 <= x < rl and 0 <= y < cl and not visited[x][y]:
visited[x][y] = True
if grid[x][y] == 0:
dist[x][y] += (step + 1)
hit[x][y] += 1
dfs(x - 1, y, step + 1)
dfs(x + 1, y, step + 1)
dfs(x, y - 1, step + 1)
dfs(x, y + 1, step + 1)
def bfs(x, y):
'''
works properly
'''
visited = [[False] * cl for _ in range(rl)]
queue =[(x, y, 0)]
while queue:
k, m, step = queue.pop(0)
for i, j in ((k - 1, m), (k + 1, m), (k, m - 1), (k, m + 1)):
if 0 <= i < rl and 0 <= j < cl and not visited[i][j]:
visited[i][j] = True
if grid[i][j] == 0:
dist[i][j] += (step + 1)
hit[i][j] += 1
queue.append((i, j, step + 1))
for i in range(rl):
for j in range(cl):
if grid[i][j] == 1:
# bfs(i, j) # this works properly
visited = [[False] * cl for _ in range(rl)]
dfs(i - 1, j, 0)
dfs(i + 1, j, 0)
dfs(i, j - 1, 0)
dfs(i, j + 1, 0)
ret = float('inf')
for i in range(rl):
for j in range(cl):
if grid[i][j] == 0 and hit[i][j] == builds:
ret = min(ret, dist[i][j])
return ret if ret != float('inf') else -1
# expect 7
print Solution().shortestDistance([[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]])
This is a kind of typical graph search problem. and usually could be solved in both DFS and BFS ways. Just can't figure out how to fix it in DFS way?
Simply DFS is not intended to find the shortest path. With some backtracking and cautious marking and unmarking of visted nodes you could use it to find all paths reaching a given point and choose the shortest one but it is unnecessarily complex and way slower than BFS.
I'm about to write some code that computes the determinant of a square matrix (nxn), using the Laplace algorithm (Meaning recursive algorithm) as written Wikipedia's Laplace Expansion.
I already have the class Matrix, which includes init, setitem, getitem, repr and all the things I need to compute the determinant (including minor(i,j)).
So I've tried the code below:
def determinant(self,i=0) # i can be any of the matrix's rows
assert isinstance(self,Matrix)
n,m = self.dim() # Q.dim() returns the size of the matrix Q
assert n == m
if (n,m) == (1,1):
return self[0,0]
det = 0
for j in range(n):
det += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).determinant())
return det
As expected, in every recursive call, self turns into an appropriate minor. But when coming back from the recursive call, it doesn't change back to it's original matrix.
This causes trouble when in the for loop (when the function arrives at (n,m)==(1,1), this one value of the matrix is returned, but in the for loop, self is still a 1x1 matrix - why?)
Are you sure that your minor returns the a new object and not a reference to your original matrix object? I used your exact determinant method and implemented a minor method for your class, and it works fine for me.
Below is a quick/dirty implementation of your matrix class, since I don't have your implementation. For brevity I have chosen to implement it for square matrices only, which in this case shouldn't matter as we are dealing with determinants. Pay attention to det method, that is the same as yours, and minor method (the rest of the methods are there to facilitate the implementation and testing):
class matrix:
def __init__(self, n):
self.data = [0.0 for i in range(n*n)]
self.dim = n
#classmethod
def rand(self, n):
import random
a = matrix(n)
for i in range(n):
for j in range(n):
a[i,j] = random.random()
return a
#classmethod
def eye(self, n):
a = matrix(n)
for i in range(n):
a[i,i] = 1.0
return a
def __repr__(self):
n = self.dim
for i in range(n):
print str(self.data[i*n: i*n+n])
return ''
def __getitem__(self,(i,j)):
assert i < self.dim and j < self.dim
return self.data[self.dim*i + j]
def __setitem__(self, (i, j), val):
assert i < self.dim and j < self.dim
self.data[self.dim*i + j] = float(val)
#
def minor(self, i,j):
n = self.dim
assert i < n and j < n
a = matrix(self.dim-1)
for k in range(n):
for l in range(n):
if k == i or l == j: continue
if k < i:
K = k
else:
K = k-1
if l < j:
L = l
else:
L = l-1
a[K,L] = self[k,l]
return a
def det(self, i=0):
n = self.dim
if n == 1:
return self[0,0]
d = 0
for j in range(n):
d += ((-1)**(i+j))*(self[i,j])*((self.minor(i,j)).det())
return d
def __mul__(self, v):
n = self.dim
a = matrix(n)
for i in range(n):
for j in range(n):
a[i,j] = v * self[i,j]
return a
__rmul__ = __mul__
Now for testing
import numpy as np
a = matrix(3)
# same matrix from the Wikipedia page
a[0,0] = 1
a[0,1] = 2
a[0,2] = 3
a[1,0] = 4
a[1,1] = 5
a[1,2] = 6
a[2,0] = 7
a[2,1] = 8
a[2,2] = 9
a.det() # returns 0.0
# trying with numpy the same matrix
A = np.array(a.data).reshape([3,3])
print np.linalg.det(A) # returns -9.51619735393e-16
The residual in case of numpy is because it calculates the determinant through (Gaussian) elimination method rather than the Laplace expansion. You can also compare the results on random matrices to see that the difference between your determinant function and numpy's doesn't grow beyond float precision:
import numpy as np
a = 10*matrix.rand(4)
A = np.array( a.data ).reshape([4,4])
print (np.linalg.det(A) - a.det())/a.det() # varies between zero and 1e-14
use Sarrus' Rule (non recursive method)
example on below link is in Javascript, but easily can be written in python
https://github.com/apanasara/Faster_nxn_Determinant
import numpy as np
def smaller_matrix(original_matrix,row, column):
for ii in range(len(original_matrix)):
new_matrix=np.delete(original_matrix,ii,0)
new_matrix=np.delete(new_matrix,column,1)
return new_matrix
def determinant(matrix):
"""Returns a determinant of a matrix by recursive method."""
(r,c) = matrix.shape
if r != c:
print("Error!Not a square matrix!")
return None
elif r==2:
simple_determinant = matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0]
return simple_determinant
else:
answer=0
for j in range(r):
cofactor = (-1)**(0+j) * matrix[0][j] * determinant(smaller_matrix(matrix, 0, j))
answer+= cofactor
return answer
#test the function
#Only works for numpy.array input
np.random.seed(1)
matrix=np.random.rand(5,5)
determinant(matrix)
Here's the function in python 3.
Note: I used a one-dimensional list to house the matrix and the size array is the amount of rows or columns in the square array. It uses a recursive algorithm to find the determinant.
def solve(matrix,size):
c = []
d = 0
print_matrix(matrix,size)
if size == 0:
for i in range(len(matrix)):
d = d + matrix[i]
return d
elif len(matrix) == 4:
c = (matrix[0] * matrix[3]) - (matrix[1] * matrix[2])
print(c)
return c
else:
for j in range(size):
new_matrix = []
for i in range(size*size):
if i % size != j and i > = size:
new_matrix.append(matrix[i])
c.append(solve(new_matrix,size-1) * matrix[j] * ((-1)**(j+2)))
d = solve(c,0)
return d
i posted this code because i couldn't fine it on the internet, how to solve n*n determinant using only standard library.
the purpose is to share it with those who will find it useful.
i started by calculating the submatrix Ai related to a(0,i).
and i used recursive determinant to make it short.
def submatrix(M, c):
B = [[1] * len(M) for i in range(len(M))]
for l in range(len(M)):
for k in range(len(M)):
B[l][k] = M[l][k]
B.pop(0)
for i in range(len(B)):
B[i].pop(c)
return B
def det(M):
X = 0
if len(M) != len(M[0]):
print('matrice non carrée')
else:
if len(M) <= 2:
return M[0][0] * M[1][1] - M[0][1] * M[1][0]
else:
for i in range(len(M)):
X = X + ((-1) ** (i)) * M[0][i] * det(submatrix(M, i))
return X
sorry for not commenting before guys :)
if you need any further explanation don't hesitate to ask .