算法编程题-数组中两个数字的最大按位与、按位或、按位异或

题目描述

之前在牛客网上刷面经的时候,看到有个同学面试腾讯的时候,遇到了这样的一道算法题,就是给定一个数组,然后在数组中选取两个数字,使得这两个数字的按位与值最大。而求两个数字异或值最大在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=bcac=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)

参考

求数组两个元素与(&)运算最大值,异或(^)运算最大值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值