题目描述
之前在牛客网上刷面经的时候,看到有个同学面试腾讯的时候,遇到了这样的一道算法题,就是给定一个数组,然后在数组中选取两个数字,使得这两个数字的按位与值最大。而求两个数字异或值最大在leetcode上也是有原题的leetcode 421。所以,总结了一下这类题型,分别是最大按位与、最大按位或、最大按位异或。
最大按位与
思路分析
选取两个数,使其按位与最大,那当然是近可能使得结果的高位为1,所以这道题目需要从高位往低位考虑。在从高位往低位考虑的过程中,如果在某一位上,数组中所有数字在这一位上为1的数量超过了2,那么一定可以选取两个数,使其按位与的结果在这一位上为1,那么其实这一个位上不为1的数字可以不用考虑了,这样就相当于删除了数组中的部分数字。但是在这一位上为1的数字数量少于2,则意味着无法选出两个数字使得按位与的结果在这一位上为1,此时继续往低位考虑即可。
示例代码
func MaxArrayAND(arr []int) int {
ans := 0
n := len(arr)
deleted := make([]byte, n)
for k := 30; k >= 0; k-- { // 第30位为符号位
// 先统计该位上为1的数字个数
count := 0
for i, num := range arr {
if deleted[i] == 0 && (num & (1 << k)) > 0 {
count++
}
}
if count < 2 { // 继续往低位
ans = 2 * ans
continue
}
ans = 2 * ans + 1
// 将为0的数字标记为删除
for i, num := range arr {
if (num & (1 << k)) == 0 {
deleted[i] = 1
}
}
}
return ans
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
最大按位或
思路分析
在一个数组中,求两个元素的最大按位或,暂时没有想到高效的办法,先写一个暴力遍历的方法,有知道的同学欢迎在评论区讨论。我觉得按位或难以处理的原因在于,两数按位或的结果,某位为1,此时这两个数在那一个位上的结果有三种可能性,难以区分讨论。
示例代码
func MaxOR(arr []int) int {
n := len(arr)
ans := 0
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
ans = max(ans, arr[i] | arr[j])
}
}
return ans
}
复杂度分析
- 时间复杂度分析: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度分析: O ( 1 ) O(1) O(1)
最大按位异或
思路分析
还是从高位到低位考虑,各位是否能够为1。首先哈希表记录所有数字从当前位到最高位的部分,然后假设当前位能够取到1,将当前结果与所有数字从当前位到最高位部分 按位异或,如果结果在哈希表中,说明当前位能够取到1,并且不会影响之前高位取到1的结果。这利用了异或运算的一个性质,如下:
a
=
b
⊕
c
↔
a
⊕
c
=
b
a=b \oplus c \leftrightarrow a \oplus c = b
a=b⊕c↔a⊕c=b
示例代码
func MaxArrXOR(arr []int) int {
ans := 0
for k := 30; k >= 0; k-- { // 第三十位为符号位
seen := make(map[int]struct{}, 0)
for _, num := range arr {
seen[num >> k] = struct{}{}
}
ans = 2 * ans + 1
var found bool
for _, num := range arr {
// 利用异或的性质,确定当前位为1是否可以做到
if _, ok := seen[(num >> k) ^ ans]; ok{
found = true
break
}
}
if !found {
ans--
}
}
return ans
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
5万+

被折叠的 条评论
为什么被折叠?



