Problem Statement in English

You’re given a 2D grid of integers. You have to determine if it’s possible to partition the grid into two non-empty parts such that the sum of the integers in both parts is equal. The partition can be made either horizontally or vertically.

Further, if removing a single cell from either part can make the sums equal, then the partition is also considered valid. However, upon removing a cell, the partition must still be connected, meaning that all remaining cells in each part must be adjacent to at least one other cell in the same part.


Approach

The way you implement this determines how easy it seems.

The idea here is that we initially assign the entire grid to the bottom parition and then row by row we move the rows to the top partition. After moving each row, we check if the sums of the two partitions are equal. If they are, we can return true immediately. If not, we check if the difference between the sums of the two partitions is equal to any of the elements in either partition. If it is, we can return true immediately as well.

But this only considers the horizontal partition. We also need to consider the vertical partition. We can do this by transposing the grid and applying the same logic as above. Reuse, reduce…rejoice :)

The connection condition is actually pretty easy to satisfy. If the cell we’re removing is in a partition whose height is just 1, then the cell to remove can only from either end, otherwise it would disconnect the partition. If the cell we’re removing is in a partition whose height is more than 1, then we can remove any cell without disconnecting the partition.

And we’re done!


Solution in Python


class Solution:
    def canPartitionGrid(self, grid: List[List[int]]) -> bool:
        def solve(grid):
            bottomFreq, bottomSum = defaultdict(int), 0
            topFreq, topSum = defaultdict(int), 0

            M, N = len(grid), len(grid[0])

            for i in range(M):
                for j in range(N):
                    v = grid[i][j]

                    bottomFreq[v] += 1
                    bottomSum += v 

            for i in range(M - 1):
                for j in range(N):
                    v = grid[i][j]

                    topFreq[v] += 1
                    topSum += v
                    
                    bottomFreq[v] -= 1
                    if not bottomFreq[v]: del bottomFreq[v]
                    bottomSum -= v

                diff_t = topSum - bottomSum
                if diff_t in topFreq:
                    if (i > 0 and N > 1) or diff_t in (grid[0][0], grid[i][N-1]):
                        return True

                diff_b = bottomSum - topSum
                if diff_b in bottomFreq:
                    if (i < M - 2 and N > 1) or diff_b in (grid[i+1][0], grid[M-1][N-1]):
                        return True

                if bottomSum == topSum: return True

            return False

        return solve(grid) or solve(list(zip(*grid)))

Complexity

  • Time: $O(M \times N)$
    Since we iterate through the grid once.

  • Space: $O(M \times N)$
    Since we store the frequency of all elements in the grid.


Mistakes I Made

I had to look this up :(


And we are done.