pythonalgorithmdepth-first-search

Python DFS Call Difference


I was trying to solve this leetcode problem involving DFS with Python: https://leetcode.com/problems/count-sub-islands/

This is my initial solution, which failed the test cases:

class Solution:

    def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int:
        ans=0

        def dfs(i,j):
            if not (0<=i<len(grid1) and 0<=j<len(grid1[0]) and grid2[i][j]):
                return True
            if (not grid2[i][j] and grid1[i][j]) or (grid2[i][j] and not grid1[i][j]):
                return False
            if grid1[i][j] and grid2[i][j]:
                grid2[i][j] = 0
                return dfs(i+1,j) and dfs(i-1,j) and dfs(i,j+1) and dfs(i,j-1)
         
        for i in range(len(grid2)):
            for j in range(len(grid2[0])):
                if grid2[i][j] and dfs(i,j):
                    ans+=1
        return ans

However, when I split up the dfs calls in the return statement like this, the code worked:

class Solution:

    def countSubIslands(self, grid1: List[List[int]], grid2: List[List[int]]) -> int:
        ans=0

        def dfs(i,j):
            if not (0<=i<len(grid1) and 0<=j<len(grid1[0]) and grid2[i][j]):
                return True
            if (not grid2[i][j] and grid1[i][j]) or (grid2[i][j] and not grid1[i][j]):
                return False
            if grid1[i][j] and grid2[i][j]:
                grid2[i][j] = 0
                #return dfs(i+1,j) and dfs(i-1,j) and dfs(i,j+1) and dfs(i,j-1)
                one=dfs(i+1,j)
                two=dfs(i-1,j)
                three=dfs(i,j+1)
                four=dfs(i,j-1)
                return one and two and three and four

        for i in range(len(grid2)):
            for j in range(len(grid2[0])):
                if grid2[i][j] and dfs(i,j):
                    ans+=1
        return ans

Can someone explain to me the difference between the dfs calls, since they seem to be equivalent to me? Thank you!

I tried the first code snippet, which didn't work. After splitting up the dfs calls in the second snippet, it worked.


Solution

  • This is caused by and's "short-circuiting" behavior, where the expression is evaluated left to right until it encounters a False value, after which it will stop evaluating that expression. When you separated out each of the dfs calls, the short-circuiting behavior was bypassed because each dfs call was executed before the and expression. But in your first code, the short-circuiting behavior of and would cause some dfs calls to not be made, making your function incorrect.

    For example, if it were to happen that dfs(i+1,j) returned a False value, then evaluation of the and expression will immediately stop there and dfs(i-1,j), dfs(i,j+1) and dfs(i,j-1) will not be called.