
2026-06-28:按位或的最小值。用go语言,给你一个大小为 m × n 的二维整数表 grid。你需要从 每一行 里 各选出一个数(同一行只选一个,不能多选或少选)。把这些被选出的数做按位或运算(bitwise OR)。
你的目标是:让最终得到的 按位或结果尽可能小。返回这个 最小可能的按位或值。
1 <= m == grid.length <= 100000。
1 <= n == grid[i].length <= 100000。
m * n <= 100000。
1 <= grid[i][j] <= 100000。
输入: grid = [[1,5],[2,4]]。
输出: 3。
解释:
从第一行选择 1,从第二行选择 2。
1 | 2 = 3,这是最小可能值。
题目来自力扣3858。
or,确定二进制遍历上限or;or。
原因:每行选最小值时,单个数字本身最小,它们的或自然是一个上界;最终答案的二进制有效位数,不会超过 or 的二进制位数,后续只需要遍历这个范围内的比特位,不用遍历全部32/64位,减少循环次数。
示例:
第一行最小1,第二行最小2,or = 1 | 2 = 3,二进制 11,有效比特位长度为2,只需处理第1位、第0位(从0开始计数)。初始 ans = 0,从最高位 i = bits.Len(uint(or)) - 1 向下循环到0,每一位执行相同逻辑:
公式:mask = ans | (1<<i - 1)
拆解掩码含义:
ans:已经确定好的高位比特(已经固定不能修改);1<<i - 1:第i位以下所有低位全部置1;
整体mask规则:掩码作用:筛选满足「高位和ans完全匹配、第i位可以为0」的候选数字。
内层遍历每一行,对每行内所有数字x做校验判断 x | mask == mask:
x | mask = mask 等价于 x & (~mask) = 0
代表x所有高于i的比特,全部和ans的高位保持一致;同时x的第i位一定是0(低位无限制)。ans |= 1 << i,把ans的第i位强制设为1,再处理下一个低位比特。初始:ans=0,or=3,二进制长度2,i从1开始(高位),再i=0。
mask = ans | (1<<1 -1) = 0 | 1 = 0b01 逐行校验:
mask = ans | (1<<0 -1) = 2 | 0 = 0b10 逐行校验:
最终ans=3,和题目输出一致。
从高到低所有比特全部判断完毕,ans就是每行选一个数得到的最小或结果。
设总元素数量 T = m * n,题目约束 T ≤ 1e5;
设数字最大二进制位数 B:grid[i][j] ≤ 1e5,1e5二进制约17位,B≈17(常数)。
代码仅使用固定数量临时变量:or、ans、i、mask、循环临时行row、数字x,无额外数组、切片、哈希表等动态存储; 不随输入规模m、n、T增长开辟存储空间。 额外空间复杂度:O(1)(常数空间)。
.
package main
import (
"fmt"
"math/bits"
"slices"
)
func minimumOR(grid [][]int) (ans int) {
or := 0
for _, row := range grid {
// 每行选个最小值,计算 OR
or |= slices.Min(row)
}
// 答案 <= or,那么答案的二进制长度也 <= or 的二进制长度
// 试填法:ans 的第 i 位能不能是 0?
// 如果在每一行的能选的数字中,都存在第 i 位是 0 的数,那么 ans 的第 i 位可以是 0,否则必须是 1
for i := bits.Len(uint(or)) - 1; i >= 0; i-- {
mask := ans | (1<<i - 1) // mask 低于 i 的比特位全是 1,表示 grid[i][j] 的低位是 0 还是 1 无所谓
next:
for _, row := range grid {
for _, x := range row {
// x 的高于 i 的比特位,如果 mask 是 0,那么 x 的这一位必须也是 0(注意 mask 继承了 ans 高位中的 0)
// x 的低于 i 的比特位,随意
// x 的第 i 个比特位,我们期望它是 0
if x|mask == mask { // x 可以选,且第 i 位是 0
continue next
}
}
// 这一行的可选数字中,第 i 位全是 1
ans |= 1 << i // ans 第 i 位必须是 1
break // 填下一位
}
}
return
}
func main() {
grid := [][]int{{1, 5}, {2, 4}}
result := minimumOR(grid)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
from typing import List
def minimumOR(grid: List[List[int]]) -> int:
# 计算每行最小值的 OR,作为答案的上界
or_val = 0
for row in grid:
or_val |= min(row)
ans = 0
# 从最高位向最低位尝试填 0
for i in range(or_val.bit_length() - 1, -1, -1):
# mask: 高于 i 的位与 ans 一致,低于 i 的位全为 1(可任意),第 i 位为 0
mask = ans | ((1 << i) - 1)
for row in grid:
for x in row:
# 如果 x 满足:高位与 ans 已固定的 0 对齐,且第 i 位为 0
if (x | mask) == mask:
break
else:
# 这一行找不到满足条件的数,第 i 位必须填 1
ans |= (1 << i)
break
return ans
if __name__ == "__main__":
grid = [[1, 5], [2, 4]]
result = minimumOR(grid)
print(result)
#include <iostream>
#include <vector>
#include <algorithm>
int minimumOR(const std::vector<std::vector<int>>& grid) {
// 计算每行最小值的按位或,作为答案的上界
int orVal = 0;
for (const auto& row : grid) {
orVal |= *std::min_element(row.begin(), row.end());
}
// 计算 orVal 的二进制长度(位数)
int bits = 0;
int tmp = orVal;
while (tmp) {
++bits;
tmp >>= 1;
}
int ans = 0;
// 试填法:从高位到低位尝试让 ans 的第 i 位为 0
for (int i = bits - 1; i >= 0; --i) {
// mask: 低于 i 的位全为 1,第 i 位为 0,高于 i 的位与 ans 保持一致
int mask = ans | ((1 << i) - 1);
bool possible = true;
for (const auto& row : grid) {
bool rowOk = false;
for (int x : row) {
// 检查 x 是否满足:高位对齐 ans 的 0 位,且第 i 位为 0
if ((x | mask) == mask) {
rowOk = true;
break;
}
}
if (!rowOk) {
possible = false;
break;
}
}
// 如果某一行无法选出第 i 位为 0 的数,则 ans 的第 i 位必须为 1
if (!possible) {
ans |= (1 << i);
}
}
return ans;
}
int main() {
std::vector<std::vector<int>> grid = {{1, 5}, {2, 4}};
int result = minimumOR(grid);
std::cout << result << std::endl;
return0;
}
