{x}
blog image

Remove All Ones With Row and Column Flips

Solution Explanation

The problem asks whether it's possible to remove all 1s from a binary matrix by flipping rows or columns. The core idea is that if we can reduce the matrix to a single unique row (or column) pattern after flipping, then we can remove all 1s.

Approach:

  1. Normalization: We choose the first row as a reference. For each subsequent row, we check if it's identical to the first row. If not, we flip the row (by XORing each element with 1). This ensures that all rows will be either identical to the first row or its inverse.

  2. Uniqueness Check: After the normalization step, we convert each row into a string and add it to a set. If the size of the set is 1, it means all rows (after potential flipping) are the same, implying we can remove all 1s. Otherwise, it's impossible.

Time Complexity Analysis:

  • The outer loop iterates through each row of the matrix (O(m)).
  • The inner loop (if a row needs flipping) iterates through each element in a row (O(n)).
  • Adding a string to a set takes O(n) time in the worst case.
  • Therefore, the overall time complexity is O(m*n).

Space Complexity Analysis:

  • The space used by the set is proportional to the number of unique rows, which is at most 2 (one for the reference row and one for its inverse). Therefore, the space complexity is O(n), dominated by the length of the string representation of a row.

Code Explanation (Python):

class Solution:
    def removeOnes(self, grid: List[List[int]]) -> bool:
        s = set()
        for row in grid:
            #If the first element of the row matches the first element of the first row, use it as is. Otherwise XOR the entire row with 1s. 
            t = tuple(row) if row[0] == grid[0][0] else tuple(x ^ 1 for x in row)
            s.add(t)
        return len(s) == 1

The Python code efficiently implements this approach. It uses a set s to store the unique row patterns. The tuple(row) converts the list to a tuple for efficient set operations. The conditional expression tuple(row) if row[0] == grid[0][0] else tuple(x ^ 1 for x in row) elegantly handles row flipping. Finally, it checks if the set size is 1 to determine the result.

Code Explanation (Java):

class Solution {
    public boolean removeOnes(int[][] grid) {
        Set<String> s = new HashSet<>();
        int n = grid[0].length;
        for (var row : grid) {
            var cs = new char[n];
            for (int i = 0; i < n; ++i) {
                cs[i] = (char) (row[0] ^ row[i]); // XOR to handle potential flipping
            }
            s.add(String.valueOf(cs));
        }
        return s.size() == 1;
    }
}

The Java code follows a similar logic, using a HashSet to store unique row patterns as strings. The crucial part is the cs[i] = (char) (row[0] ^ row[i]) line, which performs the XOR operation for potential flipping.

The other languages (C++, Go, TypeScript) demonstrate the same core algorithm with minor syntactic differences to accommodate their specific features. All share the same time and space complexity.