难度中等 110
给定 m x n
矩阵 matrix
。
你可以从中选出任意数量的列并翻转其上的 每个 单元格。(即翻转后,单元格的值从 0
变成 1
,或者从 1
变为 0
。)
返回 经过一些翻转后,行内之间所有值都相等的最大行数 。
示例 1:
输入:matrix = [[0,1],[1,1]]
输出:1
解释:不进行翻转,有 1 行所有值都相等。
示例 2:
输入:matrix = [[0,1],[1,0]]
输出:2
解释:翻转第一列的值之后,这两行都由相等的值组成。
示例 3:
输入:matrix = [[0,0,0],[0,0,1],[1,1,0]]
输出:2
解释:翻转前两列的值之后,后两行由相等的值组成。
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 300
matrix[i][j] == 0
或1
# 哈希表
: 第 列的最大行数的集合
- 当前 列可以翻与不翻,更 中每个元素比较,选择最大行数的集合作为
上述有问题:因为有可能「最大行数相同需要都要比较」,导致不断地 倍增加
只需要找互补数目,只有互补无论怎么翻不翻转,最终都是一样的
- 即:要么全等,要么相反
例如:
而: 却不行,需要每一位都互补
统计每个数目对应的「互补 / 相同数目的数量」,最后比较个数
class Solution { | |
public int maxEqualRowsAfterFlips(int[][] matrix) { | |
// 0 0 0 | |
// 0 0 1 | |
// 1 1 0 | |
// 不行,因为有可能最大行数相同需要都要比较,导致不断地 2 倍增加 | |
//dp [j]: 第 j 列的最大行数的集合 | |
// 当前 j 列可以翻与不翻,更 dp [j - 1] 中元素比较 | |
// 找互补数目,只有互补无论怎么翻不翻转,最终都是一样的 | |
// 101; 000 | |
// 010; 111 | |
// 100, 001 不行 | |
// 要互补,例如:101 去寻找 010 | |
// 统计每个数目对应的互补 / 相同数目的数量,最后比较个数 | |
Map<String, Integer> map = new HashMap<>(); | |
for (int[] row : matrix) { | |
// 不互补 | |
StringBuilder sb1 = new StringBuilder(); | |
// 互补 | |
StringBuilder sb2 = new StringBuilder(); | |
for (int v : row) { | |
sb1.append(v); | |
sb2.append(v == 0 ? 1 : 0); | |
} | |
String s1 = sb1.toString(); | |
String s2 = sb2.toString(); | |
if (map.containsKey(s1)) { | |
map.put(s1, map.get(s1) + 1); | |
} else if (map.containsKey(s2)) { | |
map.put(s2, map.get(s2) + 1); | |
} else { | |
// 都没有 | |
map.put(s1, 1); | |
} | |
} | |
int ans = 0; | |
for (Integer value : map.values()) { | |
ans = Math.max(value, ans); | |
} | |
return ans; | |
} | |
} |
# 哈希表 + 异或优化
可以对上述使用异或优化以下,对开头为 的元素进行翻转
例如: 与 ,若二者互补,则开头必然相反,则统一将开头为 的元素进行翻转
- 0 ^ [0] = 0,0 ^ [1] = 1
- 1 ^ [1] = 0,1 ^ [0] = 1
class Solution { | |
public int maxEqualRowsAfterFlips(int[][] matrix) { | |
// 0 0 0 | |
// 0 0 1 | |
// 1 1 0 | |
// 不行,因为有可能最大行数相同需要都要比较,导致不断地 2 倍增加 | |
//dp [j]: 第 j 列的最大行数的集合 | |
// 当前 j 列可以翻与不翻,更 dp [j - 1] 中元素比较 | |
// 找互补数目,只有互补无论怎么翻不翻转,最终都是一样的 | |
// 101; 000 | |
// 010; 111 | |
// 100, 001 不行 | |
// 要互补,例如:101 去寻找 010 | |
// 统计每个数目对应的互补 / 相同数目的数量,最后比较个数 | |
Map<String, Integer> map = new HashMap<>(); | |
int m = matrix[0].length; | |
for (int[] row : matrix) { | |
// 统一将元素 1 开头的元素翻转 | |
int v = row[0]; | |
char[] cs = new char[m]; | |
for (int i = 0; i < m; i++) { | |
cs[i] = (char) (row[i] ^ v + '0'); | |
} | |
String s = new String(cs); | |
map.put(s, map.getOrDefault(s, 0) + 1); | |
} | |
int ans = 0; | |
for (Integer value : map.values()) { | |
ans = Math.max(value, ans); | |
} | |
return ans; | |
} | |
} |