0

I'm working on LeetCode 1582. Special Positions in a Binary Matrix. How could I make a function that uses recursion and DFS to return the count of how many special positions are in a m x n binary matrix. A position (i, j) is called special if matrix[i][j] == 1 and all other elements in row i and column j are 0 (rows and columns are 0-indexed).

Example 1

Input: mat = [[1,0,0],[0,0,1],[1,0,0]]
Output: 1
Explanation: (1, 2) is a special position because mat[1][2] == 1 and all other elements in row 1 and column 2 are 0.

Example 2

Input: mat = [[1,0,0],[0,1,0],[0,0,1]]
Output: 3
Explanation: (0, 0), (1, 1) and (2, 2) are special positions.

This is what I have so far, but I am stumped on how to correctly execute the DFS recursion given this problem.

class Solution:
    def numSpecial(self, mat: List[List[int]]) -> int:
        count = 0
        for ir, rval in enumerate(mat):
            for ic, cval in enumerate(rval):
                if cval == 1:
                    if self.dfs([ir, ic], mat):
                        count += 1
        return count

                        
    def dfs(self, idx, mat):
        if self.isvalid(idx, mat):
            if mat[idx[0]][idx[1]] != 0:
                return False
            else:
                north = [idx[0]-1, idx[1]]
                self.dfs(north)
                south = [idx[0]+1, idx[1]]
                self.dfs(south)
                east = [idx[0], idx[1]+1]
                self.dfs(east)
                west = [idx[0], idx[1]-1]
                self.dfs(west)
                return True # dont know if and where I should put this return True
        
    
    def isvalid(self, idx, mat):
        if idx[0] in range(0,len(mat)):
            if idx[1] in range(0,len(mat[0])):
                return True
        return False
        

Also, I understand that there are many simpler ways to solve this problem, but I just want to be able to solve it using DFS recursion like how I was attempting to above

croatoan
  • 31
  • 4
  • Interesting problem. I think maybe you need to just return when you have an invalid index i.e. you don't need a boolean. Maybe you need to have a global variable that keeps track of how many ones you've found so far. And if it gets to 2, then return False. If it's 1 at the end of the dfs, then return true... Or maybe the dfs returns an integer, the number of ones found so far. And it bottoms out as soon as 2 are seen. If it's 2 in the calling code then you know it's not special. – davo36 Feb 27 '22 at 03:57
  • I'm having a bit of a play with this. 2 other problems with your code: 1) The recursive calls don't pass 'mat' as a parameter, 2) The dfs code searches the whole array, not just the row and column that you want to. Because say you move down a row, you then go each of the 4 directions from there... – davo36 Feb 27 '22 at 04:34

1 Answers1

0

Ok, so this code works. I had to add a bit of stuff. A couple of global variables which are a bit naughty, but I don't know how to do it without them.

One is simply the number of ones we have come across in our DFS search so far. We want this to be exactly 1 after our DFS has finished. That being the cell we start the DFS from.

And I use a 2D array of booleans to keep track of where the search has already been otherwise it would go on forever.

Note that I also added a check to the isvalid routine to make sure we're only considering the values in the same row or column as the cell we're checking.

# Evil global variables
numOnesFound = 0
visited = []

class Solution:

def numSpecial(self, mat: List[List[int]]) -> int:
    global numOnesFound
    global visited
    
    count = 0
    for rowIndex, row in enumerate(mat):
        for colIndex, colValue in enumerate(row):
            if colValue == 1:
                numOnesFound = 0
                visited = [[False for x in range(len(mat[0]))] for y in range(len(mat))]
                self.dfs([rowIndex, colIndex], [rowIndex, colIndex], mat)
                if numOnesFound == 1:
                    count += 1
    return count

           


def dfs(self, startingPosition, idx, mat):
    global numOnesFound
    global visited
    
    if numOnesFound >= 2:
        return
    
    if self.isvalid(startingPosition, idx, mat):
        
        if visited[idx[0]][idx[1]]:
            return
        visited[idx[0]][idx[1]] = True

        if mat[idx[0]][idx[1]] != 0:
            numOnesFound += 1
        
        north = [idx[0]-1, idx[1]]
        self.dfs(startingPosition, north, mat)
        south = [idx[0]+1, idx[1]]
        self.dfs(startingPosition, south, mat)
        east = [idx[0], idx[1]+1]
        self.dfs(startingPosition, east, mat)
        west = [idx[0], idx[1]-1]
        self.dfs(startingPosition, west, mat)
    return
    

def isvalid(self, startingPosition, idx, mat):
    
    # Check to see if we're in the same column or same row as the startingPosition
    if idx[0] == startingPosition[0] or idx[1] == startingPosition[1]:
        # Check to see the indexes are within 0->height 0->width 
        if idx[0] in range(0,len(mat)):
            if idx[1] in range(0,len(mat[0])):
                return True
            
    return False
davo36
  • 694
  • 9
  • 19