Finding the number of paths in a maze with obstacles - python

I've been working on this leetcode problem, which is essentially finding the number of valid paths in a maze given some obstacleGrid matrix. If obstacleGrid[i][j] == 1, then we have an obstacle at (i,j) and we have zero otherwise, which a valid spot. We can only move down and right with the goal of starting from the upper left to the bottom right.
I have written the code below:
def uniquePathsWithObstacles(self, obstacleGrid):
# obstruction at the start
if (obstacleGrid[0][0] == 1): return 0
# obstruction at the end
if (obstacleGrid[-1][-1] == 1): return 0
m, n = len(obstacleGrid), len(obstacleGrid[0])
memo = [[0] * n] * m
# starting move
memo[0][0] = 1
# now check the first row
for j in range(1, n):
memo[0][j] = 1 if (obstacleGrid[0][j] == 0 and memo[0][j-1] != 0) else 0
# now check the first column
for i in range(1, m):
memo[i][0] = 1 if (obstacleGrid[i][0] == 0 and memo[i-1][0] != 0) else 0
# now check everything else
for i in range(1, m):
for j in range(1, n):
if (obstacleGrid[i][j] == 1): memo[i][j] = 0
else: memo[i][j] = memo[i-1][j] + memo[i][j-1]
return memo[-1][-1]
I took the obvious DP approach and I know the idea works but something is wrong with the code; for some reason I don't think my memo matrix is being updated properly? I feel like the problem is staring at me in the face but for some reason I can't see it. Any help appreciated!
Edit: For obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] and if I had a print(memo) right before the return statement, I get [[1, 1, 2], [1, 1, 2], [1, 1, 2]]. This happens to give me the right answer, but the memo matrix is wrong!

One problem lies in the line memo = [[0] * n] * m.
This does not really create mcopies of the same list, but instead, it only creates the [0] * n list once and then creates memo as a list of m references to this list. Any change to any of these lists therefore modifies all other lists!
You can try this yourself:
memo = [[0] * 3] * 4
memo[0][1] = 1
print(memo)
This gives [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]].
Instead, you have to initialize each list on their own, e.g.,
memo = []
for i in range(m):
memo.append([0] * n)

I just tried to do this with recursion as an comparison rather than an answer.
import numpy as np
def number_of_paths(obstacles):
"""
Calculate the number of paths available in a maze with obstacles, with only right and down moves, from top left
to bottom right.
Args:
obstacles (ndarray): binary matrix with 1 representing obstacle
Returns:
int: the number of paths
"""
if obstacles[0,0] == 1:
raise ValueError # cannot start on an obstacle
count = 0
if obstacles.shape == (2,1):
return 1
if obstacles.shape == (1,2):
return 1
if obstacles.shape[1] > 1 and obstacles[0,1] == 0:
count += number_of_paths(obstacles[:,1:])
if obstacles.shape[0] > 1 and obstacles[1,0] == 0:
count += number_of_paths(obstacles[1:,:])
return count

your code is correct and 1 line must be updated per the below:
def uniquePathsWithObstacles(self, obstacleGrid):
# obstruction at the start
if (obstacleGrid[0][0] == 1): return 0
# obstruction at the end
if (obstacleGrid[-1][-1] == 1): return 0
m, n = len(obstacleGrid), len(obstacleGrid[0])
memo = [[0] * n for i in range(m)]
# starting move
memo[0][0] = 1
# now check the first row
for j in range(1, n):
#memo[0][j] = 1 if (obstacleGrid[0][j] == 0 and memo[0][j-1] != 0) else 0
memo[0][j] = 1 if (obstacleGrid[0][j] == 0 and memo[0][j-1] != 0) else 0
# now check the first column
for i in range(1, m):
memo[i][0] = 1 if (obstacleGrid[i][0] == 0 and memo[i-1][0] != 0) else 0
# now check everything else
for i in range(1, m):
for j in range(1, n):
if (obstacleGrid[i][j] == 1): memo[i][j] = 0
else: memo[i][j] = memo[i-1][j] + memo[i][j-1]
return memo[-1][-1]

Related

how to write a python code to display magic square matrix according to user input?

This is a program to print a matrix whose sum of each row , column or diagonal elements are equal.
I have a working code but my program gives same output each time i run it. I need a program to print different matrix output for same input.
def matrix(n):
m = [[0 for x in range(n)]for y in range(n)]
i = n // 2
j = n - 1
num = 1
while num <= (n * n):
if i == -1 and j == n:
j = n - 2
i = 0
else:
if j == n:
j = 0
if i < 0:
i = n - 1
if m[int(i)][int(j)]:
j = j - 2
i = i + 1
continue
else:
m[int(i)][int(j)] = num
num = num + 1
j = j + 1
i = i - 1
print ("Sum of eggs in each row or column and diagonal : ",int(n*(n*n+1)/2),"\n")
for i in range(0, n):
for j in range(0, n):
print('%2d ' % (m[i][j]),end = '')
if j == n - 1:
print()
n=int(input("Number of rows of the matrix : "))
matrix(n)
I am unsure whether this is what you are looking for, but one solution is to add a random number to each value of the matrix, as this doesn't break the property
a matrix whose sum of each row, column or diagonal elements are equal.
Here is how you could do it:
add = random.randint(0, 50)
m = [[v+add for v in row] for row in m]
Moreover, you can rotate and add two magic squares without loosing their property. Therefore, you can rotate the magic square you have and add it to the original. This can add some nonlinearity to the results.
def rotate(m): # 90 degrees counter clockwise
return [[m[j][i] for j in range(len(m))] for i in range(len(m[0])-1, -1, -1)]
# add the matrix with its rotated version
m = list(map(lambda e: [sum(x) for x in zip(*e)], zip(m, rotate(m))))
I hope this helps!

Generate Randomized Color Board

generate a random (height x width) grid such that for every coordinate (i, j), there can be no three consecutive same colors in a row or in a column.
generate(int: width, int: height, list: colors)
Example:
getvalidMatrix(3, 3, [0, 1, 2])
output:
[
[1, 2, 1],
[1, 0, 2],
[0, 1, 2],
]
import random
def getvalidMatrix(length,width,colors):
map = dict()
for i in range(len(colors)):
map[colors[i]]=i
res = [[0] * length] * width
for i in range(length):
for j in range(width):
end = len(colors)
if i - 1 >= 0 and i - 2 >= 0 and res[i-1][j] == res[i-2][j]:
index = map[res[i-1][j]]
colors[index] = colors[end]
colors[end] = map[res[i-1]][j]
end -= 1
if j - 1 >= 0 and j - 2 >= 0 and res[i][j-1] == res[i][j-2]:
index = map[res[i][j-1]]
colors[index] = colors[end]
colors[end] = map[res[i][j-1]]
end -= 1
next=random.randint(0,end)
res[i][j] = colors[next]
return res
if __name__ == '__main__':
length = 3
width = 3
colors = [0,1,2]
print(getvalidMatrix(length, width, colors))
I got IndexError: list index out of range with the code above. Which part of the code should I fix in order to avoid the IndexError?
Although I didn't completely understand de algorithm used to solve the problem, I can see that you are committing a few mistakes:
You're retrieving a multidimensional list element incorrectly, e.g., list_var[a][b] instead of list_var[b][a]. This can be solved in the for loops.
You're indexing variable colors this way: colors[end] = ..., but variable end is initialized as end = len(colors), i.e., with a value 1 unit greater than the maximum index allowed, remember that lists are zero-indexed.
A misplaced closing bracket.
Here's the corrected code. Run a file diff to see the changes I've made. I don't guarantee it now solves the problem you were given but the errors you came across are gone.
import random
def getvalidMatrix(length,width,colors):
map = dict()
for i in range(len(colors)):
map[colors[i]]=i
res = [[0] * length] * width
for i in range(width):
for j in range(length):
end = len(colors)-1
if i - 1 >= 0 and i - 2 >= 0 and res[i-1][j] == res[i-2][j]:
index = map[res[i-1][j]]
colors[index] = colors[end]
colors[end] = map[res[i-1][j]]
end -= 1
if j - 1 >= 0 and j - 2 >= 0 and res[i][j-1] == res[i][j-2]:
index = map[res[i][j-1]]
colors[index] = colors[end]
colors[end] = map[res[i][j-1]]
end -= 1
next=random.randint(0,end)
res[i][j] = colors[next]
return res
if __name__ == '__main__':
length = 3
width = 3
colors = [0,1,2]
print(getvalidMatrix(length, width, colors))

Find time needed for vertices to stop disappearing

I am given undirected graph that consists of N vertices numbered from 0 to N-1 connected with M edges.The graph is described by two arrays, A and B both of length M. A pair ([A[k],B[k]) describes edge between A[k] and B[k] for k from 0 to M-1.
Each second every vertex with at most 1 edge connected to disappears.Every edge which is connected to one of disappearing vertices also disappears.
After how many seconds will the vertices stop disappearing.
For N=7, ((0,1),(1,2),(2,0),(1,4),(4,5),(4,6)) answer should be 2.
def solution(N,A,B):
d2 = dict.fromkeys(range(N), 0)
count = 0
arr = []
for i in range(len(A)):
arr.append((A[i],B[i]))
while True:
for i in range(len(A)+1):
for c in arr:
if i in c:
d2[i] += 1
arr1 = arr
for i in range(len(A)+1):
if d2[i] <= 1:
arr = list(filter(lambda x: x[1] != i and x[0] != i, arr))
if len(arr) == len(arr1):
return count + 1
break
count += 1
Here is my code.For this test case (4, [0, 1, 2, 3], [1, 2, 3, 0]) it outputs Keyerror: 4. Can you help me to solve the problem.Thank you.
Try this (I inserted a couple of print() to let you see what's going on):
def solution(N, A, B):
linked = defaultdict(list)
for i in range(len(A)):
linked[A[i]].append(B[i])
linked[B[i]].append(A[i])
changed = True
seconds = 0
removing = []
while changed:
changed = False
seconds += 1
print(f'second {seconds}')
for i in list(linked.keys())[:]:
if len(linked[i]) > 1:
continue
if len(linked[i]) == 1:
removing.append((linked[i][0],i))
del linked[i]
changed = True
for i,j in removing:
print(f'remove {j} from {i}')
linked[i].remove(j)
removing = []
return seconds - 1

Largest subarray with sum equal to 0

This is a typical interview question. Given an array that contains both positive and negative elements without 0, find the largest subarray whose sum equals 0. I tried to solve this. This is what I came up with.
def sub_array_sum(array,k=0):
start_index = -1
hash_sum = {}
current_sum = 0
keys = set()
best_index_hash = {}
for i in array:
start_index += 1
current_sum += i
if current_sum in hash_sum:
hash_sum[current_sum].append(start_index)
keys.add(current_sum)
else:
if current_sum == 0:
best_index_hash[start_index] = [(0,start_index)]
else:
hash_sum[current_sum] = [start_index]
if keys:
for k_1 in keys:
best_start = hash_sum.get(k_1)[0]
best_end_list = hash_sum.get(k_1)[1:]
for best_end in best_end_list:
if abs(best_start-best_end) in best_index_hash:
best_index_hash[abs(best_start-best_end)].append((best_start+1,best_end))
else:
best_index_hash[abs(best_start-best_end)] = [(best_start+1,best_end)]
if best_index_hash:
(bs,be) = best_index_hash[max(best_index_hash.keys(),key=int)].pop()
return array[bs:be+1]
else:
print "No sub array with sum equal to 0"
def Main():
a = [6,-2,8,5,4,-9,8,-2,1,2]
b = [-8,8]
c = [-7,8,-1]
d = [2200,300,-6,6,5,-9]
e = [-9,9,-6,-3]
print sub_array_sum(a)
print sub_array_sum(b)
print sub_array_sum(c)
print sub_array_sum(d)
print sub_array_sum(e)
if __name__ == '__main__':
Main()
I am not sure if this will satisfy all the edge case. if someone can comment on that, it would be excellent Also i want to extend this to sum equalling to any K not just 0. How should i go about it. And any pointers to optimize this further is also helpful.
You have given a nice, linear-time solution (better than the two other answers at this time, which are quadratic-time), based on the idea that whenever sum(i .. j) = 0, it must be that sum(0 .. i-1) = sum(0 .. j) and vice versa. Essentially you compute the prefix sums sum(0 .. i) for all i, building up a hashtable hash_sum in which hash_sum[x] is a list of all positions i having sum(0 .. i) = x. Then you go through this hashtable, one sum at a time, looking for any sum that was made by more than one prefix. Among all such made-more-than-once sums, you choose the one that was made by a pair of prefixes that are furthest apart -- this is the longest.
Since you already noticed the key insight needed to make this algorithm linear-time, I'm a bit puzzled as to why you build up so much unnecessary stuff in best_index_hash in your second loop. For a given sum x, the furthest-apart pair of prefixes that make that sum will always be the smallest and largest entries in hash_sum[x], which will necessarily be the first and last entries (because that's the order they were appended), so there's no need to loop over the elements in between. In fact you don't even need a second loop at all: you can keep a running maximum during your first loop, by treating start_index as the rightmost endpoint.
To handle an arbitrary difference k: Instead of finding the leftmost occurrence of a prefix summing to current_sum, we need to find the leftmost occurrence of a prefix summing to current_sum - k. But that's just first_with_sum{current_sum - k}.
The following code isn't tested, but should work:
def sub_array_sum(array,k=0):
start_index = -1
first_with_sum = {}
first_with_sum{0} = -1
best_start = -1
best_len = 0
current_sum = 0
for i in array:
start_index += 1
current_sum += i
if current_sum - k in first_with_sum:
if start_index - first_with_sum{current_sum - k} > best_len:
best_start = first_with_sum{current_sum - k} + 1
best_len = start_index - first_with_sum{current_sum - k}
else:
first_with_sum{current_sum} = start_index
if best_len > 0:
return array[best_start:best_start+best_len-1]
else:
print "No subarray found"
Setting first_with_sum{0} = -1 at the start means that we don't have to treat a range beginning at index 0 as a special case. Note that this algorithm doesn't improve on the asymptotic time or space complexity of your original one, but it's simpler to implement and will use a small amount less space on any input that contains a zero-sum subarray.
Here's my own answer, just for fun.
The number of subsequences is quadratic, and the time to sum a subsequence is linear, so the most naive solution would be cubic.
This approach is just an exhaustive search over the subsequences, but a little trickery avoids the linear summing factor, so it's only quadratic.
from collections import namedtuple
from itertools import chain
class Element(namedtuple('Element', ('index', 'value'))):
"""
An element in the input sequence. ``index`` is the position
of the element, and ``value`` is the element itself.
"""
pass
class Node(namedtuple('Node', ('a', 'b', 'sum'))):
"""
A node in the search graph, which looks like this:
0 1 2 3
\ / \ / \ /
0-1 1-2 2-3
\ / \ /
0-2 1-3
\ /
0-3
``a`` is the start Element, ``b`` is the end Element, and
``sum`` is the sum of elements ``a`` through ``b``.
"""
#classmethod
def from_element(cls, e):
"""Construct a Node from a single Element."""
return Node(a=e, b=e, sum=e.value)
def __add__(self, other):
"""The combining operation depicted by the graph above."""
assert self.a.index == other.a.index - 1
assert self.b.index == other.b.index - 1
return Node(a=self.a, b=other.b, sum=(self.sum + other.b.value))
def __len__(self):
"""The number of elements represented by this node."""
return self.b.index - self.a.index + 1
def get_longest_k_sum_subsequence(ints, k):
"""The longest subsequence of ``ints`` that sums to ``k``."""
n = get_longest_node(n for n in generate_nodes(ints) if n.sum == k)
if n:
return ints[n.a.index:(n.b.index + 1)]
if k == 0:
return []
def get_longest_zero_sum_subsequence(ints):
"""The longest subsequence of ``ints`` that sums to zero."""
return get_longest_k_sum_subsequence(ints, k=0)
def generate_nodes(ints):
"""Generates all Nodes in the graph."""
nodes = [Node.from_element(Element(i, v)) for i, v in enumerate(ints)]
while len(nodes) > 0:
for n in nodes:
yield n
nodes = [x + y for x, y in zip(nodes, nodes[1:])]
def get_longest_node(nodes):
"""The longest Node in ``nodes``, or None if there are no Nodes."""
return max(chain([()], nodes), key=len) or None
if __name__ == '__main__':
def f(*ints):
return get_longest_zero_sum_subsequence(list(ints))
assert f() == []
assert f(1) == []
assert f(0) == [0]
assert f(0, 0) == [0, 0]
assert f(-1, 1) == [-1, 1]
assert f(-1, 2, 1) == []
assert f(1, -1, 1, -1) == [1, -1, 1, -1]
assert f(1, -1, 8) == [1, -1]
assert f(0, 1, -1, 8) == [0, 1, -1]
assert f(5, 6, -2, 1, 1, 7, -2, 2, 8) == [-2, 1, 1]
assert f(5, 6, -2, 2, 7, -2, 1, 1, 8) == [-2, 1, 1]
I agree with sundar nataraj when he says that this must be posted to the code review forum.
For fun though I looked at your code. Though I am able to understand your approach, I fail to understand the need to use Counter.
best_index_hash[start_index] = [(0,start_index)] - Here best_index_hash is of the type Counter. Why are you assigning a list to it?
for key_1, value_1 in best_index_hash.most_common(1) - You trying to get largest subsequence and for that you are using most_common as the answer. This is not intuitive semantically.
I am tempted to post a solution but I will wait for you to edit the code snippet and improve it.
Addendum
For fun, I had a go at this puzzle and I present my effort below. I make no guarantees of correctness/completeness.
from collections import defaultdict
def max_sub_array_sum(a, s):
if a:
span = defaultdict(lambda : (0,0))
current_total = 0
for i in xrange(len(a)):
current_total = a[i]
for j in xrange (i + 1, len(a)):
current_total += a[j]
x,y = span[current_total]
if j - i > y - x:
span[current_total] = i,j
if s in span:
i, j = span[s]
print "sum=%d,span_length=%d,indices=(%d,%d),sequence=%s" %\
(s, j-i + 1, i, j, str(a[i:j + 1]))
return
print "Could not find a subsequence of sum %d in sequence %s" % \
(s, str(a))
max_sub_array_sum(range(-6, -1), 0)
max_sub_array_sum(None, 0)
max_sub_array_sum([], 0)
max_sub_array_sum(range(6), 15)
max_sub_array_sum(range(6), 14)
max_sub_array_sum(range(6), 13)
max_sub_array_sum(range(6), 0)
Here's the solution taken from LeetCode :
def sub_array_sum(nums, k=0):
count, sum = 0, 0
map = dict()
map[0] = 1
for i in range(len(nums)):
sum += nums[i]
if map.__contains__(sum - k):
count += map[sum - k]
map[sum] = map.get(sum, 0) + 1
return count

Finding turning points of an Array in python

If I for example have an array:
A = (0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6)
It can be seen that there are 4 turning points. (at A[4],A[6], A[13], A[17])
How can I use python to return the number of turning points?
import numpy as np
import scipy.integrate as SP
import math
def turningpoints(A):
print A
N = 0
delta = 0
delta_prev = 0
for i in range(1,19):
delta = A[i-1]-A[i] #Change between elements
if delta < delta_prev: #if change has gotten smaller
N = N+1 #number of turning points increases
delta_prev = delta #set the change as the previous change
return N
if __name__ == "__main__":
A = np.array([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6])
print turningpoints(A)
Currently, this system is flawed and certainly not very elegant. Any ideas?
If you have numpy:
def turningpoints(lst):
dx = np.diff(lst)
return np.sum(dx[1:] * dx[:-1] < 0)
Or the non-numpy equivalent version:
def turningpoints(lst):
dx = [x - y for x, y in zip(lst[1:], lst[:-1])]
return sum(dx1 * dx2 < 0 for dx1, dx2 in zip(dx[1:], dx[:-1]))
And just for the love of one-liners:
def turningpoints(lst):
return sum(x0*x1 + x1*x2 < x1*x1 + x0*x2 for x0, x1, x2 in zip(lst[2:], lst[1:-1], lst[:-2]))
But the readability is arguably decreased on this one :)
I know it's an old question, but I just had the same problem and as Cardin stated in the comments of Malvolio's answer, the answer cannot handle successive points with the same value like [1, 2, 3, 4, 4, 4, 3, 2, 1]. My implementation can handle this problem.
Although, it returns two lists with the indices of the minimum and maximum turning points.
def turning_points(array):
''' turning_points(array) -> min_indices, max_indices
Finds the turning points within an 1D array and returns the indices of the minimum and
maximum turning points in two separate lists.
'''
idx_max, idx_min = [], []
if (len(array) < 3):
return idx_min, idx_max
NEUTRAL, RISING, FALLING = range(3)
def get_state(a, b):
if a < b: return RISING
if a > b: return FALLING
return NEUTRAL
ps = get_state(array[0], array[1])
begin = 1
for i in range(2, len(array)):
s = get_state(array[i - 1], array[i])
if s != NEUTRAL:
if ps != NEUTRAL and ps != s:
if s == FALLING:
idx_max.append((begin + i - 1) // 2)
else:
idx_min.append((begin + i - 1) // 2)
begin = i
ps = s
return idx_min, idx_max
To correctly answer the question, the number of turning points is then computed as:
sum(len(x) for x in turning_points(X))
Example
You're overthinking it. A "turning point" is one that is either higher than the points on both sides, or lower.
def turningpoints(x):
N=0
for i in range(1, len(x)-1):
if ((x[i-1] < x[i] and x[i+1] < x[i])
or (x[i-1] > x[i] and x[i+1] > x[i])):
N += 1
return N
>>> turningpoints([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6])
4
>>> def turns(L):
... answer, delta = 0, -1 if L[1]<L[0] else 1
... i = 2
... while i < len(L):
... d = -1 if L[i]<L[i-1] else 1
... if d != delta:
... answer += 1
... delta = d
... i += 1
... return answer
...
>>> L = [0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6]
>>> turns(L)
4
def group_in_threes(slicable):
for i in range(len(slicable)-2):
yield slicable[i:i+3]
def turns(L):
for index, three in enumerate(group_in_threes(L)):
if (three[0] > three[1] < three[2]) or (three[0] < three[1] > three[2]):
yield index + 1
>>> list(turns([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6]))
[4, 6, 13, 17]
>>> len(_)
4

Categories

Resources