# LeetCode 1072: Flip Columns For Maximum Number of Equal Rows

## Problem Restatement

We are given an `m x n` binary matrix.

In one operation, we choose any column and flip all values in it (0 → 1, 1 → 0).

We want to maximize the number of rows that have all the same value (all-0 or all-1) after any number of column flips.

The official constraints state that `1 <= m, n <= 300`.

## Input and Output

| Item | Meaning |
|---|---|
| Input | Binary matrix |
| Output | Maximum rows that can be all-equal after column flips |

Function shape:

```python
def maxEqualRowsAfterFlips(matrix: list[list[int]]) -> int:
    ...
```

## Examples

Example 1:

```python
matrix = [[0,1],[1,1]]
```

Flip column 0: `[[1,1],[0,1]]`. Row 0 is `[1,1]`. One all-equal row.

Answer:

```python
1
```

Example 2:

```python
matrix = [[0,1],[1,0]]
```

No flips: row 0 = `[0,1]`, row 1 = `[1,0]`. Flip column 0: `[[1,1],[0,0]]`. Both rows all-equal.

Answer:

```python
2
```

## Key Insight

Two rows can be made all-equal simultaneously if and only if they are identical or exact complements (one is the bitwise NOT of the other).

Normalize each row to its canonical form: if the row starts with `1`, flip it. Then count the most common pattern.

## Algorithm

1. For each row, compute a canonical key:
   - If `row[0] == 1`, flip all bits.
   - Otherwise keep as is.
2. Count occurrences of each pattern.
3. Return the maximum count.

## Correctness

Two rows can be simultaneously made all-0 or all-1 if and only if they are identical or complementary. Normalizing (always starting with 0) groups identical and complementary rows together.

## Edge Cases

- Duplicates usually matter; store counts when a set would lose necessary multiplicity.
- Update the frequency structure in the same order the invariant assumes.
- Check empty or one-element inputs if the problem allows them.

## Complexity

| Metric | Value | Why |
|---|---:|---|
| Time | `O(m * n)` | Normalize and count each row |
| Space | `O(m * n)` | Counter for row patterns |

## Common Pitfalls

- Do not optimize away the invariant; the code should still make it clear what condition is being maintained.
- Prefer problem-specific names over one-letter variables once the logic becomes stateful.

## Implementation

```python
from collections import Counter

class Solution:
    def maxEqualRowsAfterFlips(self, matrix: list[list[int]]) -> int:
        def key(row):
            if row[0] == 1:
                return tuple(1 - x for x in row)
            return tuple(row)

        return max(Counter(key(row) for row in matrix).values())
```

## Testing

```python
def run_tests():
    s = Solution()

    assert s.maxEqualRowsAfterFlips([[0,1],[1,1]]) == 1
    assert s.maxEqualRowsAfterFlips([[0,1],[1,0]]) == 2
    assert s.maxEqualRowsAfterFlips([[0,0,0],[0,0,1],[1,1,0]]) == 2

    print("all tests passed")

run_tests()
```

| Test | Expected | Why |
|---|---:|---|
| `[[0,1],[1,1]]` | `1` | Only one row can be made all-equal |
| `[[0,1],[1,0]]` | `2` | Complementary rows, flip makes both uniform |
| 3-row matrix | `2` | Two rows share the same pattern |

