How to fix my code for Traverse Diagonal Matrix (alterate version)? - python

I have the following code which is used to print diagonal matrix alternatively. Please look at my code and tell me what is wrong with it ?
class Solution:
def findDiagonalOrder(self, matrix: List[List[int]]) -> List[int]:
# No. of rows
m=len(matrix)
# No. of columns
n=len(matrix[0])
# Counter to alternatively switch the direction.
up=True
# list to store the result
l=[]
i,j,count=0,0,0
# loop for traversing all the elements.
while(count<=m*n):
if(up):
while(i>=0 and j<n):
l.append(matrix[i][j])
count+=1
i-=1
j+=1
if(i<0 and j<n):
i=0
if(j==n):
i=i+2
j=j-1
else:
while(j>=0 and i<m):
l.append(matrix[i][j])
count+=1
j-=1
i+=1
if(j<0 and i<m):
j=0
if(i==m):
j=j+2
i=i-1
up= not up
print(l)
Input :
[
[1,2,3],
[4,5,6],
[7,8,9]
]
Expected Answer :
[1,2,4,7,5,3,6,8,9]
Actual Answer :
Line 22: IndexError: list index out of range

Your code works, just change your while (count <= m * n) to while (count < m * n).
def findDiagonalOrder(matrix):
# No. of rows
m = len(matrix)
# No. of columns
n = len(matrix[0])
# Counter to alternatively switch the direction.
up = True
# list to store the result
l = []
i, j, count = 0, 0, 0
# loop for traversing all the elements.
while (count < m * n):
if (up):
while (i >= 0 and j < n):
l.append(matrix[i][j])
count += 1
i -= 1
j += 1
if (i < 0 and j < n):
i = 0
if (j == n):
i = i + 2
j = j - 1
else:
while (j >= 0 and i < m):
l.append(matrix[i][j])
count += 1
j -= 1
i += 1
if (j < 0 and i < m):
j = 0
if (i == m):
j = j + 2
i = i - 1
up = not up
print(l)
matrix = [
[1,2,3],
[4,5,6],
[7,8,9]
]
findDiagonalOrder(matrix)
#[1, 2, 4, 7, 5, 3, 6, 8, 9]

Related

python find biggest sequence of zeros in list of lists (recursion)

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)

The number of combinations of the number 196225

I wanted to write a program that will show the number of combinations of the number 196225 but I failed because it showed very strange numbers and I can't quite understand why
my code:
list = []
liczba = [1,9,6,2,2,5]
n_num = 0
iter=0
#ijlkmn
for i in range(6):
n_num = liczba[i]*10**5
for j in range(6):
if j != i:
n_num += liczba[j]*10**4
for l in range(6):
if l != i and l != j:
n_num += liczba[l]*10**3
for k in range(6):
if k != i and k != j and k!= l:
n_num += liczba[k]*10**2
for m in range(6):
if m != i and m != j and m != l and m!= k:
n_num += liczba[m]*10
for n in range(6):
if n != i and n != j and n != l and n!= k and n!= m:
n_num += liczba[n]
if (n_num in list) == False:
list.append(n_num)
iter += 1
I know it looks very primitive but I only wanted the result which turned out to be incorrect, here are some of its numbers ~
196225, 196277, 196502, 196554, 197076, 197098, 199723, 199775, 200040
could someone tell me where did these numbers come from?
if you want to make all the possible numbers using tose digits , you can use itertools module :
import itertools
liczba = [1, 9, 6, 2, 2, 5]
numbers = itertools.permutations(liczba, 6)
for num in numbers:
print(num)
You are adding to previous answers on each of your internal loops. Because the value of n_num is not reset at each iteration. For example:
digits = [1,2,3]
for k in range(3):
n_num = digits[k]*10**2
for k2 in range(3):
if k2!=k:
n_num += digits[k2]*10
print(n_num)
prints
120
150
210
240
310
330
because when k2 = 2 the first time, 30 is added to 120 yielding 150... etc etc
I see what's wrong with your code - let's look into smaller example to see it clearly and find a solution
liczba = [1, 2, 3]
for i in range(3):
n_num = liczba[i] * 10 ** 2 # it start with 1 * 100 = 100, good one!
for j in range(3):
if j != i: # for j = 0 it just pass
n_num += liczba[j] * 10 # j = 1, n_num is now 100 + 20 = 120
for l in range(3):
if l != i and l != j: we skip 0 and 1
n_num += liczba[l] # n_num = 123, great
list.append(n_num)
Now we back to second loop:
for j in range(3): # j jumps to 2
if j != i:
n_num += liczba[j] * 10 # wait - here is the problem, our n_num should be 100 here again but now it's 123, so we add 30 to previous solution
for l in range(3):
if l != i and l != j: # l = 1
n_num += liczba[l] # adding 2, but instead of 100 + 30 + 2 we have 123 + 30 + 2
list.append(n_num)
How to fix it? Very simple - you can just calculate number once at the end. You have all indexes already, so write
n_num = liczba[i] * 10 ** 5 + liczba[j] * 10 ** 4 + ...
And one small hint for the end - if you use set instead of list you won't need a check if n_num is already in result.

I am not getting any output from the provided partitioning algorithm

The given program below is supposed to randomly pick an element from the list i.e piv and return the list in which all the elements smaller than piv are on the left side and larger elements are on the right side of the piv in the list . But I am getting no output, just blank screen.
sample INPUT:[7,9,4,8,3,6,2,5]
if piv=8 one of the possible outputs OUTPUT:[4,3,2,7,6,5,8,9]
import random
def swap(arr,a,b):
arr[a],arr[b]=arr[b],arr[a]
return arr
def partition(arr,n):
piv=random.choice(arr)
j=(n-1)
i=0
while(i<j):
if(arr[i]<piv and arr[j]<piv):
i+=1
elif(arr[i]>piv and arr[j]>piv):
j-=1
elif(arr[i]>piv and arr[j]<piv):
swap(arr,i,j)
j-=1
i+=1
elif(arr[i]<piv and arr[j]>piv):
j-=1
i+=1
return arr
z=[7,9,4,8,3,6,2,5]
y=partition(z,8)
print(y)
You just have to add some greater than or equal signs, since the algorithm doesn't take into account that piv and the value can be the same.
import random
def swap(arr, a, b):
arr[a], arr[b] = arr[b], arr[a]
return arr
def partition(arr, n):
piv = random.choice(arr)
print(piv)
j = (n-1)
i = 0
while(i < j):
if(arr[i] < piv and arr[j] < piv):
i += 1
elif(arr[i] > piv and arr[j] > piv):
j -= 1
elif(arr[i] >= piv and arr[j] <= piv):
swap(arr, i, j)
j -= 1
i += 1
elif(arr[i] <= piv and arr[j] >= piv):
j -= 1
i += 1
return arr
z = [7, 9, 4, 8, 3, 6, 2, 5]
y = partition(z, 8)
print(y)
import random
def swap(arr,a,b):
arr[a],arr[b]=arr[b],arr[a]
return arr
def partition(arr,n):
piv=random.randint(0,len(arr)-1)#randomly chooses an integer to be pivot
print(arr)
#print(piv, arr[piv])
print("The partition is being done around element :" , arr[piv])
#print(arr)
arr[len(arr)-1],arr[piv] = arr[piv],arr[len(arr)-1]#swaps pivot with last element
#print(arr)#updated array
i = -1
j = 0
pivot = arr[len(arr)-1]
for j in range(len(arr)):
if(arr[j] < pivot):
i += 1
arr[i],arr[j] = arr[j],arr[i]
arr[i+1],arr[len(arr)-1] = arr[len(arr)-1],arr[i+1]
return arr
z=[7,9,4,8,3,6,2,5]
y=partition(z,8)
print(y)

Python efficient way to write nested if-else inside nested for-loop

I'm working on a code challenge in which I have to reduce the execution time as much as possible, the only thing I able to find where I can make an improvement is a nested if-else statement inside a nested for-loop but I'm not sure how it can be improvided.
Here's my code:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i,n+1,1):
if i == j:
pass
else:
if getEnemyStatus(mat, i, j):
break
else:
if isEnemy(enemyDict, i, j):
setStatus(mat, i, j)
break
else:
count += 1
value of n can be from 1 to 10^5
You can skip the first if condition by starting with i+1 in range
for j in range(i+1, n+1, 1):
# code here
Second, nested if else condition should be avoided with elif for reading purpose.
Update code should be like:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i + 1, n + 1, 1):
if getEnemyStatus(mat, i, j):
break
elif isEnemy(enemyDict, i, j):
setStatus(mat, i, j)
break
else:
count += 1
NOTE: Also if you can set the status setStatus in your isEnemy function then you can get more cleaner code:
mat = [[0] * n] * n
count = 0
for i in range(n,0,-1):
count += 1
for j in range(i + 1, n + 1, 1):
if getEnemyStatus(mat, i, j) or isEnemy(enemyDict, i, j):
break
count += 1

Merge sort implementation in python giving incorrect result

I am trying to implement the merge sort algorithm described in these notes by Jeff Erickson on page 3. but even though the algorithm is correct and my implementation seems correct, I am getting the input list as output without any change. Can someone point out the anomalies, if any, in it.
def merge(appnd_lst, m):
result = []
n = len(appnd_lst)
i, j = 0, m
for k in range(0, n):
if j < n:
result.append(appnd_lst[i])
i += 1
elif i > m:
result.append(appnd_lst[j])
j += 1
elif appnd_lst[i] < appnd_lst[j]:
result.append(appnd_lst[i])
i += 1
else:
result.append(appnd_lst[j])
j += 1
return result
def mergesort(lst):
n = len(lst)
if n > 1:
m = int(n / 2)
left = mergesort(lst[:m])
right = mergesort(lst[m:])
appnd_lst = left
appnd_lst.extend(right)
return merge(appnd_lst, m)
else:
return lst
if __name__ == "__main__":
print mergesort([3, 4, 8, 0, 6, 7, 4, 2, 1, 9, 4, 5])
There are three errors in your merge function a couple of indexing errors and using the wrong comparison operator. Remember python list indices go from 0 .. len(list)-1.
* ...
6 if j > n-1: # operator wrong and off by 1
* ...
9 elif i > m-1: # off by 1
* ...

Categories