Identifying a Valid Row Subset in a Binary Matrix via Bitmasking

In a binary matrix of size m x n, a subset of rows is considered "good" if, for every column, the sum of the elements in that column does not exceed half the size of the subset. Formally, if the subset conntains k rows, the sum of each column must be less than or equal to floor(k / 2). The goal is to return the indices of such a subset in ascending order.

Mathematical Intuition

The problem constraints, specifically the small number of columns (typically $n \le 5$ in this specific challenge), allow us to simplify the search space. Instead of checking all possible combinations of rows, we can observe the following:

  • If a subset of size k = 1 is "good," it must be a row consisting entirely of zeros. In this case, the sum of any column is 0, which is $\le \lfloor 1/2 \rfloor = 0$.
  • If a subset of size k = 2 is "good," the sum of any column must be $\le \lfloor 2/2 \rfloor = 1$. This means that for any two rows selected, they cannot both have a 1 in the same column. Bitwise, this translates to (rowA & rowB) == 0.
  • For $n \le 5$, if a "good" subset exists, there will always be a valid subset of size 1 or 2. Larger subsets are unnecessary to evaluate given the constraints.

Algorithmic Approach

Since the number of columns is small, we can treat each row as a bitmask. For example, a row [1, 0, 1] can be represented by the integer 5 ($2^0 + 2^2$).

  1. Iterate through the matrix and convert each unique row into its bitmask representation.
  2. Store the mapping of bitmasks to their original row indices. Using a hash map or an array (since there are only $2^5 = 32$ possible masks) is efficient.
  3. Check for a zero mask: If it exists, return its index as a single-element subset.
  4. Perform a nested loop over the unique masks found. If two masks mask1 and mask2 satisfy (mask1 & mask2) == 0, return their indices.

Implementation

The following C++ implementation utilizes a map to store the first occurrence of each unique row bitmask.

#include <vector>
#include <unordered_map>
#include <algorithm>

class Solution {
public:
    std::vector<int> goodSubsetofBinaryMatrix(std::vector<std::vector<int>>& matrix) {
        int rows = matrix.size();
        int cols = matrix[0].size();
        std::unordered_map<int, int> maskToIndex;

        for (int i = 0; i < rows; ++i) {
            int currentMask = 0;
            for (int j = 0; j < cols; ++j) {
                if (matrix[i][j] == 1) {
                    currentMask |= (1 << j);
                }
            }
            
            // Case 1: Row with all zeros is a valid subset of size 1
            if (currentMask == 0) {
                return {i};
            }
            
            // Only store the first occurrence of a specific mask
            if (maskToIndex.find(currentMask) == maskToIndex.end()) {
                maskToIndex[currentMask] = i;
            }
        }

        // Case 2: Check pairs of rows for a valid subset of size 2
        for (auto const& [maskA, indexA] : maskToIndex) {
            for (auto const& [maskB, indexB] : maskToIndex) {
                if (indexA != indexB && (maskA & maskB) == 0) {
                    std::vector<int> result = {indexA, indexB};
                    std::sort(result.begin(), result.end());
                    return result;
                }
            }
        }

        return {};
    }
};

Complexity Analysis

  • Time Complexity: $O(M \times N + 2^{2N})$, where $M$ is the number of rows and $N$ is the number of columns. Processing the matrix takes $O(M \times N)$. The nested loop over masks takes $O((2^N)^2)$. Given $N \le 5$, $2^{10}$ is constant time (1024 iterations).
  • Space Complexity: $O(2^N)$ to store the indices for each unique bitmask pattern.

Tags: bitmask matrix algorithms C++ Optimization

Posted on Thu, 16 Jul 2026 16:05:53 +0000 by jsinker