I am given an (nxm) matrix of positive and negative integers.
The goal is to try and convert all negative numbers into positive ones, and if this is possible, return the number of passes of the matrix required to do this, otherwise return -1.
Here are the rules:
- You can only convert a negative number into a positive one, if the negative number has an adjacent (directly above, below, left or right) entry that is positive.
- If you convert a number from negative to positive in a certain pass, you cannot then use this (recently) turned positive number to turn other negative numbers positive- at least for this pass.
I have written an accepted solution to the problem, but I can’t seem to work out the Time Complexity of the solution.
My solution:
-
Create a
Boolean matrixto mark the negative entries that have been turned positive in the current pass (we will reset this matrix after each pass) -
Iterate over all entries of the matrix
-
For every negative number we stumble across check all 4 of its adjacent entries and see if there are any positive entries.
If so, convert it to positive and mark it in the boolean matrix. -
Increment
number of passeseach time we iterate over the whole matrix. -
We are done when we iterate over the entire matrix and have not made a single change to it (i.e. conversion from negative to positive).
-
If there are any negative entries left,
return -1, otherwise return thenumber of passes.
I can’t seem to think of a worst case- any suggestions on the time complexity of this solution?
My initial thought are that it is O(n), where n is the size of the matrix.
For reference, here is my solution:
def minimumPassesOfMatrix(matrix):
numberOfPasses = 0
ChangesMade = True
while ChangesMade:
negToPosMarket = [[False for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
ChangesMade = False
for row in range(len(matrix)):
for col in range(len(matrix[0])):
if matrix[row][col] < 0:
positiveAdjacent = checkAdjacentEntriesForPositive(matrix, row, col, negToPosMarket)
if positiveAdjacent:
matrix[row][col] *= -1
negToPosMarket[row][col] = True
ChangesMade = True
if not ChangesMade:
break
numberOfPasses += 1
if all(matrix[row][col] >= 0 for row in range(len(matrix)) for col in range(len(matrix[0]))): #notebook double for loop list comp!
return numberOfPasses
print(matrix)
return -1
def checkAdjacentEntriesForPositive(matrix, row, col, negToPosMarket):
matrixHeight = len(matrix) - 1
matrixWidth = len(matrix[0]) - 1
if not OutOfBounds(row + 1, col, matrixHeight, matrixWidth) and not negToPosMarket[row + 1][col]:
if matrix[row + 1][col] > 0:
return True
if not OutOfBounds(row - 1, col, matrixHeight, matrixWidth) and not negToPosMarket[row - 1][col]:
if matrix[row - 1][col] > 0:
return True
if not OutOfBounds(row, col + 1, matrixHeight, matrixWidth) and not negToPosMarket[row][col + 1]:
if matrix[row][col + 1] > 0:
return True
if not OutOfBounds(row, col - 1, matrixHeight, matrixWidth) and not negToPosMarket[row][col - 1]:
if matrix[row][col - 1] > 0:
return True
return False
def OutOfBounds(row, col, matrixHeight, matrixWidth):
return row < 0 or col < 0 or row > matrixHeight or col > matrixWidth
>Solution :
The worst case scenario would be a positive number at one corner of the matrix with everything else being negative. This will require n+m passes to flip the opposite corner. The total time would be (n+m)xnxm if you go through every position on each pass.
If you use a set of coordinates instead, this can be reduced to nxm
Place the coordinates of positive values in a set. At each pass convert their negative neighbours to positive and place these former negatives into a new set for the next pass. This way, you only process each item once.
Here’s a example in Python:
def makePos(matrix):
m = len(matrix)
n = len(matrix[0])
plusCoords = {(r,c) for r,row in enumerate(matrix)
for c,val in enumerate(row)
if val>0} # initial set of + coordinates
passes = 0
iterations = 0
while plusCoords: # more passes for new + coordinates
passes += 1 # count passes
nextCoords = set() # coordinates of new positives
for r,c in plusCoords: # go through this pass's coords
iterations += 1
for dr,dc in [(-1,0),(0,-1),(0,1),(1,0)]: # neigbors
nr,nc = r+dr, c+dc
if nr not in range(m): continue
if nc not in range(n): continue
if matrix[nr][nc] < 0: # flip to positive
nextCoords.add((nr,nc)) # track flips
for nr,nc in nextCoords:
matrix[nr][nc] *= -1 # update matrix
plusCoords = nextCoords # coords for next pass
return passes or -1, iterations
M = [ [10,-1,-1,-1,-1],
[-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1]]
print(*makePos(M)) # 7 15 (7 passes,15 iterations)