列表

详情


2397. 被列覆盖的最多行数

给你一个下标从 0 开始的 m x n 二进制矩阵 mat 和一个整数 cols ,表示你需要选出的列数。

如果一行中,所有的 1 都被你选中的列所覆盖,那么我们称这一行 被覆盖 了。

请你返回在选择 cols 列的情况下,被覆盖 的行数 最大 为多少。

 

示例 1:

输入:mat = [[0,0,0],[1,0,1],[0,1,1],[0,0,1]], cols = 2
输出:3
解释:
如上图所示,覆盖 3 行的一种可行办法是选择第 0 和第 2 列。
可以看出,不存在大于 3 行被覆盖的方案,所以我们返回 3 。

示例 2:

输入:mat = [[1],[0]], cols = 1
输出:2
解释:
选择唯一的一列,两行都被覆盖了,原因是整个矩阵都被覆盖了。
所以我们返回 2 。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int maximumRows(vector<vector<int>>& matrix, int numSelect) { } };

cpp 解法, 执行用时: 4 ms, 内存消耗: 8.7 MB, 提交时间: 2024-01-04 07:46:24

class Solution {
public:
    int maximumRows(vector<vector<int>> &mat, int numSelect) {
        int m = mat.size(), n = mat[0].size();
        vector<int> mask(m);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                mask[i] |= mat[i][j] << j;
            }
        }

        int ans = 0;
        int subset = (1 << numSelect) - 1;
        while (subset < (1 << n)) {
            int coveredRows = 0;
            for (int row : mask) {
                if ((row & subset) == row) {
                    coveredRows++;
                }
            }
            ans = max(ans, coveredRows);
            int lb = subset & -subset;
            int x = subset + lb;
            subset = ((subset ^ x) / lb >> 2) | x;
        }
        return ans;
    }
};

java 解法, 执行用时: 1 ms, 内存消耗: 40.2 MB, 提交时间: 2024-01-04 07:46:10

public class Solution {
    public int maximumRows(int[][] mat, int numSelect) {
        int m = mat.length, n = mat[0].length;
        int[] mask = new int[m];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                mask[i] |= mat[i][j] << j;
            }
        }

        int ans = 0;
        int subset = (1 << numSelect) - 1;
        while (subset < (1 << n)) {
            int coveredRows = 0;
            for (int row : mask) {
                if ((row & subset) == row) {
                    coveredRows++;
                }
            }
            ans = Math.max(ans, coveredRows);
            int lb = subset & -subset;
            int x = subset + lb;
            subset = ((subset ^ x) / lb >> 2) | x;
        }
        return ans;
    }
}

java 解法, 执行用时: 2 ms, 内存消耗: 39.2 MB, 提交时间: 2023-08-10 17:55:58

class Solution {
    public int maximumRows(int[][] mat, int cols) {
        int m = mat.length;
        int n = mat[0].length;
        int state = 1 << n;
        int[] arr = new int[m];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (mat[i][j] == 1) {
                    arr[i] ^= (1 << j);
                }
                
            }
        }
        int res = 0;
        for (int i = 0; i < state; i++) {
            if (Integer.bitCount(i) == cols) {
                // System.out.println("状态:" + Integer.toBinaryString(i));
                int count = 0;
                for (int x : arr) {
                    if ((((~i) & x) << (32 - n)) == 0) {
                        count++;
                    }
                }
                res = Math.max(res, count);
            }
        }
        return res;
    }
}

cpp 解法, 执行用时: 4 ms, 内存消耗: 8.3 MB, 提交时间: 2023-08-10 17:55:41

// 把每一行转换为一个int数,遍历2^(列) - 1个列
// 如果列数的1的个数为cols,统计 (列数 & 行) == 行的所有行的总数,并更新ret
class Solution {
public:
    int maximumRows(vector<vector<int>>& mat, int cols) {
        int n = mat.size(), m = mat[0].size();
        vector<int> row_int(n);
        for (int i = 0; i < n; i ++) {
            int num = 0;
            for (int j = 0; j < m; j ++) {
                num *= 2;
                num += mat[i][j];
            }
            row_int[i] = num;
        }
        // for (int i = 0; i < n; i ++) 
        //     cout << row_int[i] << " ";
        int now = 1, ret = 0, cnt = 0;
        while (now < (1 << m)) {
            if (__builtin_popcount(now) == cols) {
                for (int i = 0; i < n; i ++) 
                    // 这里一定要注意 C++ &的优先级低于 == 下面的括号不能省略
                    if ((row_int[i] & now) == row_int[i]) cnt ++;
                ret = max(ret, cnt);
                cnt = 0;
            }
            now ++;
        }
        return ret;
    }
};

python3 解法, 执行用时: 48 ms, 内存消耗: 15.9 MB, 提交时间: 2023-08-10 17:55:02

class Solution:
    def maximumRows(self, mat: List[List[int]], cols: int) -> int:
        ans = 0
        mask = [sum(v << j for j, v in enumerate(row)) for i, row in enumerate(mat)]
        set = (1 << cols) - 1
        while set < 1 << len(mat[0]):
            # row & set = row 表示 row 是 set 的子集,所有 1 都被覆盖
            ans = max(ans, sum(row & set == row for row in mask))
            lb = set & -set
            x = set + lb
            set = (set ^ x) // lb >> 2 | x
        return ans

golang 解法, 执行用时: 0 ms, 内存消耗: 2 MB, 提交时间: 2023-08-10 17:53:55

// gopher's hack
func maximumRows(mat [][]int, cols int) (ans int) {
	m, n := len(mat), len(mat[0])
	mask := make([]int, m)
	for i, row := range mat {
		for j, v := range row {
			mask[i] |= v << j
		}
	}
	for set := 1<<cols - 1; set < 1<<n; {
		cnt := 0
		for _, row := range mask {
			if row&set == row { // row 是 set 的子集,所有 1 都被覆盖
				cnt++
			}
		}
		ans = max(ans, cnt)
		lb := set & -set
		x := set + lb
		// 下式等价于 set = (set^x)/lb>>2 | x
		set = (set^x)>>bits.TrailingZeros(uint(lb))>>2 | x
	}
	return
}

func max(a, b int) int { if b > a { return b }; return a }

golang 解法, 执行用时: 0 ms, 内存消耗: 2 MB, 提交时间: 2023-08-10 17:52:59

func maximumRows(mat [][]int, cols int) (ans int) {
	m, n := len(mat), len(mat[0])
	mask := make([]int, m)
	for i, row := range mat {
		for j, v := range row {
			mask[i] |= v << j
		}
	}
	for set := 0; set < 1<<n; set++ {
		if bits.OnesCount(uint(set)) != cols { // 跳过大小不等于 cols 的集合
			continue
		}
		cnt := 0
		for _, row := range mask {
			if row&set == row { // row 是 set 的子集,所有 1 都被覆盖
				cnt++
			}
		}
		ans = max(ans, cnt)
	}
	return
}

func max(a, b int) int { if b > a { return b }; return a }

python3 解法, 执行用时: 52 ms, 内存消耗: 15.9 MB, 提交时间: 2023-08-10 17:52:22

'''
由于数据范围很小,我们可以枚举所有大小为 cols 的列编号的集合,
对于每个集合,遍历 mat,统计所有 1 被覆盖的行的个数,个数的最大值即为答案。

代码实现时,我们可以用二进制表示集合,二进制的第 i 位为 1 表示 i 在集合中,
为 0 表示 i 不在集合中。这样可以用二进制枚举集合,同时把 mat 的每一行也用二进制表示,
从而做到 O(1) 判断行中的所有 1 是否被覆盖。
'''
class Solution:
    def maximumRows(self, mat: List[List[int]], cols: int) -> int:
        ans = 0
        mask = [sum(v << j for j, v in enumerate(row)) for i, row in enumerate(mat)]
        for set in range(1 << len(mat[0])):
            # 集合的大小等于 cols,符合题目要求
            if set.bit_count() == cols:
                # row & set = row 表示 row 是 set 的子集,所有 1 都被覆盖
                ans = max(ans, sum(row & set == row for row in mask))
        return ans

上一题