给定 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.lengthn == matrix[i].length1 <= m, n <= 300matrix[i][j] == 0 或 1 
方法一:哈希 思路与算法 
题目给定 m\times n 的矩阵,要求从中选取任意数量的列并翻转其上的每个单元格。单元格仅包含 0 或者 1。问最多可以得到多少个由相同元素组成的行。如果某一行全部是 1 或者全部是 0,则表示该行由相同元素组成。
如果翻转固定的某些列,可以使得两个不同的行都变成由相同元素组成的行,那么我们称这两行为本质相同的行。例如 001 和 110 就是本质相同的行。
本质相同的行有什么特点呢?可以发现,本质相同的行只存在两种情况,一种是由 0 开头的行,另一种是由 1 开头的行。在开头的元素确定以后,由于翻转的列已经固定,所以可以推断出后续所有元素是 0 还是 1。
为了方便统计本质相同的行的数量,我们让由 1 开头的行全部翻转,翻转后行内元素相同的行即为本质相同的行。之后我们将每一行转成字符串形式存储到哈希表中,遍历哈希表得到最多的本质相同的行的数量即为答案。
代码 
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class  Solution  {public :    int  maxEqualRowsAfterFlips (vector<vector<int >>& matrix)           int  m = matrix.size (), n = matrix[0 ].size ();         unordered_map<string, int > mp;         for  (int  i = 0 ; i < m; i++) {             string s = string (n, '0' );             for  (int  j = 0 ; j < n; j++) {                                  s[j] = '0'  + (matrix[i][j] ^ matrix[i][0 ]);             }             mp[s]++;         }         int  res = 0 ;         for  (auto  &[k, v] : mp) {             res = max (res, v);         }         return  res;     } }; 
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  Solution  {    public  int  maxEqualRowsAfterFlips (int [][] matrix)  {         int  m  =  matrix.length, n = matrix[0 ].length;         Map<String, Integer> map = new  HashMap <String, Integer>();         for  (int  i  =  0 ; i < m; i++) {             char [] arr = new  char [n];             Arrays.fill(arr, '0' );             for  (int  j  =  0 ; j < n; j++) {                                  arr[j] = (char ) ('0'  + (matrix[i][j] ^ matrix[i][0 ]));             }             String  s  =  new  String (arr);             map.put(s, map.getOrDefault(s, 0 ) + 1 );         }         int  res  =  0 ;         for  (Map.Entry<String, Integer> entry : map.entrySet()) {             res = Math.max(res, entry.getValue());         }         return  res;     } } 
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 class  Solution :    def  maxEqualRowsAfterFlips (self, matrix: List [List [int ]] ) -> int :         m, n = len (matrix), len (matrix[0 ])         count = Counter()         for  i in  range (m):             value = 0              for  j in  range (n):                                  value = value * 10  + (matrix[i][j] ^ matrix[i][0 ])             count[value] += 1          return  max (count.values()) 
[sol1-Go] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func  maxEqualRowsAfterFlips (matrix [][]int ) int  {    m, n := len (matrix), len (matrix[0 ])     mp := make (map [string ]int )     for  i := 0 ; i < m; i++ {         arr := make ([]byte , n)         for  j := 0 ; j < n; j++ {                          if  matrix[i][j] ^ matrix[i][0 ] == 0  {                 arr[j] = '0'              } else  {                 arr[j] = '1'              }         }         s := string (arr)         mp[s]++     }     res := 0      for  _, value := range  mp {         if  value > res {             res = value         }     }     return  res } 
[sol1-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var  maxEqualRowsAfterFlips = function (matrix ) {    let  m = matrix.length , n = matrix[0 ].length ;     let  map = {};     for  (let  i = 0 ; i < m; i++) {         let  arr = new  Array (n).fill ('0' );         for  (let  j = 0 ; j < n; j++) {                          arr[j] = '0'  + (matrix[i][j] ^ matrix[i][0 ]);         }         let  s = arr.join ('' );         map[s] = (map[s] || 0 ) + 1 ;     }     let  res = 0 ;     for  (let  key in  map) {         res = Math .max (res, map[key]);     }     return  res; } 
[sol1-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  class  Solution  {    public  int  MaxEqualRowsAfterFlips (int [][] matrix         int  m = matrix.Length, n = matrix[0 ].Length;         IDictionary<string , int > dictionary = new  Dictionary<string , int >();         for  (int  i = 0 ; i < m; i++) {             char [] arr = new  char [n];             Array.Fill(arr, '0' );             for  (int  j = 0 ; j < n; j++) {                                  arr[j] = (char ) ('0'  + (matrix[i][j] ^ matrix[i][0 ]));             }             string  s = new  string (arr);             dictionary.TryAdd(s, 0 );             dictionary[s]++;         }         int  res = 0 ;         foreach  (KeyValuePair<string , int > pair in  dictionary) {             res = Math.Max(res, pair.Value);         }         return  res;     } } 
[sol1-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 typedef  struct  {    char  *key;     int  val;     UT_hash_handle hh; } HashItem; HashItem *hashFindItem (HashItem **obj, char  *key)  {     HashItem *pEntry = NULL ;     HASH_FIND_STR(*obj, key, pEntry);     return  pEntry; } bool  hashAddItem (HashItem **obj, char  *key, int  val)  {    if  (hashFindItem(obj, key)) {         return  false ;     }     HashItem *pEntry = (HashItem *)malloc (sizeof (HashItem));     pEntry->key = key;     pEntry->val = val;     HASH_ADD_STR(*obj, key, pEntry);     return  true ; } bool  hashSetItem (HashItem **obj, char  *key, int  val)  {    HashItem *pEntry = hashFindItem(obj, key);     if  (!pEntry) {         hashAddItem(obj, key, val);     } else  {         pEntry->val = val;     }     return  true ; } int  hashGetItem (HashItem **obj, char  *key, int  defaultVal)  {    HashItem *pEntry = hashFindItem(obj, key);     if  (!pEntry) {         return  defaultVal;     }     return  pEntry->val; } void  hashFree (HashItem **obj)  {    HashItem *curr = NULL , *tmp = NULL ;     HASH_ITER(hh, *obj, curr, tmp) {         HASH_DEL(*obj, curr);         free (curr->key);         free (curr);     } } #define  MAX(a, b) ((a) > (b) ? (a) : (b)) int  maxEqualRowsAfterFlips (int ** matrix, int  matrixSize, int * matrixColSize)  {    int  m = matrixSize, n = matrixColSize[0 ];     HashItem *mp = NULL ;     for  (int  i = 0 ; i < m; i++) {         char  *s = (char  *)calloc (n + 1 , sizeof (char ));         memset (s, '0' , sizeof (char ) * n);         for  (int  j = 0 ; j < n; j++) {                          s[j] = '0'  + (matrix[i][j] ^ matrix[i][0 ]);         }         hashSetItem(&mp, s, hashGetItem(&mp, s, 0 ) + 1 );     }     int  res = 0 ;     for  (HashItem *pEntry = mp; pEntry != NULL ; pEntry = pEntry->hh.next) {         res = MAX(res, pEntry->val);     }     hashFree(&mp);     return  res; } 
复杂度分析