Medium
题目描述
给你一个大小为 m x n 的二维整数数组 grid。
你必须从网格的每一行中恰好选择一个整数。
返回一个整数,表示从每行选择的整数的最小可能按位或值。
示例 1:
输入:grid = [[1,5],[2,4]]
输出:3
解释:
从第一行选择 1,从第二行选择 2。
1 | 2 = 3 的按位或值是最小可能的。
示例 2:
输入:grid = [[3,5],[6,4]]
输出:5
解释:
从第一行选择 5,从第二行选择 4。
5 | 4 = 5 的按位或值是最小可能的。
示例 3:
输入:grid = [[7,9,8]]
输出:7
解释:
选择 7 可以得到最小的按位或值。
约束条件:
1 <= m == grid.length <= 10^51 <= n == grid[i].length <= 10^5m * n <= 10^51 <= grid[i][j] <= 10^5
解题思路
这道题要求我们从每行选择一个数,使得所有选择数字的按位或值最小。
核心思路:贪心 + 位运算
按位或运算有一个重要性质:一旦某个位被设置为1,就无法通过后续的或运算变回0。因此,我们应该尽可能避免设置高位的位。
算法步骤:
- 从最高位开始检查每一位(通常检查到第17位就足够,因为数字最大为10^5)
- 对于当前位,检查是否可以在每一行都找到至少一个数字,使得该位为0
- 如果可以,则该位在最终结果中保持为0;否则该位必须为1
- 使用动态规划或贪心策略:维护当前可能的最小或值集合
优化思路: 我们可以用集合来维护每一步可能的所有或值。对于每一行,我们将当前集合中的每个值与该行的每个数字进行或运算,得到新的可能值集合。为了避免集合过大,我们只保留较小的值。
由于按位或的单调性,如果我们已经有了值A,而A的所有位都包含在B中(即A | B = B),那么B就可以被A替代,因为A更小且能产生相同或更好的结果。
代码实现
class Solution {
public:
int minimumOR(vector<vector<int>>& grid) {
set<int> current = {0};
for (auto& row : grid) {
set<int> next;
for (int val : current) {
for (int num : row) {
next.insert(val | num);
}
}
current = move(next);
// 优化:只保留较小的值,因为按位或是单调递增的
if (current.size() > 50) {
set<int> pruned;
int count = 0;
for (int val : current) {
pruned.insert(val);
if (++count >= 50) break;
}
current = move(pruned);
}
}
return *current.begin();
}
};
class Solution:
def minimumOR(self, grid: List[List[int]]) -> int:
current = {0}
for row in grid:
next_set = set()
for val in current:
for num in row:
next_set.add(val | num)
current = next_set
# 优化:只保留较小的值
if len(current) > 50:
current = set(sorted(current)[:50])
return min(current)
public class Solution {
public int MinimumOR(int[][] grid) {
HashSet<int> current = new HashSet<int> { 0 };
foreach (var row in grid) {
HashSet<int> next = new HashSet<int>();
foreach (int val in current) {
foreach (int num in row) {
next.Add(val | num);
}
}
current = next;
// 优化:只保留较小的值
if (current.Count > 50) {
var sortedValues = current.OrderBy(x => x).Take(50);
current = new HashSet<int>(sortedValues);
}
}
return current.Min();
}
}
/**
* @param {number[][]} grid
* @return {number}
*/
var minimumOR = function(grid) {
let current = new Set([0]);
for (let row of grid) {
let next = new Set();
for (let val of current) {
for (let num of row) {
next.add(val | num);
}
}
current = next;
// 优化:只保留较小的值
if (current.size > 50) {
let sortedValues = Array.from(current).sort((a, b) => a - b).slice(0, 50);
current = new Set(sortedValues);
}
}
return Math.min(...current);
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(m × n × k),其中 k 是每步保留的状态数量,通常为常数 |
| 空间复杂度 | O(k),用于存储可能的或值集合 |