Flip Columns For Maximum Number of Equal Rows
Two rows become identical after some column flips iff they're equal or exact complements; bucket-count both forms.
Problem#
Given a binary m x n matrix, you may flip any subset of columns (toggle all bits in each chosen column). Return the maximum number of rows that can be made identical after some choice of flips.
Examples#
[[0,1],[1,1]]→1[[0,1],[1,0]]→2[[0,0,0],[0,0,1],[1,1,0]]→2
Constraints#
1 <= m, n <= 300,matrix[i][j]is0or1.
Approach#
Two rows can be made equal by some flip set iff they are equal or exact bitwise complements. Canonicalize each row to “always starts with 0” (flip the row if it starts with 1), hash-count canonical forms, and return the most frequent.
Solution#
class Solution {public: int maxEqualRowsAfterFlips(vector<vector<int>>& matrix) { unordered_map<string, int> freq; int n = matrix[0].size(); for (auto& row : matrix) { string key(n, '0'); int leader = row[0]; for (int j = 0; j < n; ++j) key[j] = ('0' + (row[j] ^ leader)); ++freq[key]; } int best = 0; for (auto& [_, c] : freq) best = max(best, c); return best; }};func maxEqualRowsAfterFlips(matrix [][]int) int { freq := map[string]int{} n := len(matrix[0]) for _, row := range matrix { key := make([]byte, n) leader := row[0] for j := 0; j < n; j++ { key[j] = byte('0' + (row[j] ^ leader)) } freq[string(key)]++ } best := 0 for _, c := range freq { if c > best { best = c } } return best}from collections import Counterfrom typing import List
class Solution: def maxEqualRowsAfterFlips(self, matrix: List[List[int]]) -> int: freq: Counter = Counter() for row in matrix: leader = row[0] key = tuple(v ^ leader for v in row) freq[key] += 1 return max(freq.values())var maxEqualRowsAfterFlips = function(matrix) { const freq = new Map(); const n = matrix[0].length; for (const row of matrix) { const leader = row[0]; let key = ''; for (let j = 0; j < n; j++) key += (row[j] ^ leader); freq.set(key, (freq.get(key) || 0) + 1); } let best = 0; for (const c of freq.values()) { if (c > best) best = c; } return best;};class Solution { public int maxEqualRowsAfterFlips(int[][] matrix) { Map<String, Integer> freq = new HashMap<>(); int n = matrix[0].length; for (int[] row : matrix) { int leader = row[0]; StringBuilder sb = new StringBuilder(n); for (int j = 0; j < n; j++) sb.append((char) ('0' + (row[j] ^ leader))); String key = sb.toString(); freq.merge(key, 1, Integer::sum); } int best = 0; for (int c : freq.values()) best = Math.max(best, c); return best; }}function maxEqualRowsAfterFlips(matrix: number[][]): number { const freq = new Map<string, number>(); const n = matrix[0].length; for (const row of matrix) { const leader = row[0]; let key = ''; for (let j = 0; j < n; j++) key += (row[j] ^ leader); freq.set(key, (freq.get(key) ?? 0) + 1); } let best = 0; for (const c of freq.values()) { if (c > best) best = c; } return best;}Editorial#
The XOR canonicalization picks a single representative per equivalence class. Any column-flip choice that makes one row all-zero would equally make every row in its class all-zero — so the largest class is the answer.
Complexity#
- Time: O(m*n).
- Space: O(m*n).
Concept revision#
Related#