421. Maximum XOR of Two Numbers in an Array

本文介绍了一种在数组中寻找两个元素进行异或操作得到最大值的算法,并提供了两种实现方式:一种是通过哈希集合优化查找过程,另一种是利用Trie树结构高效存储和查询。这两种方法都能有效地在O(n)的时间复杂度内解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.

Find the maximum result of ai XOR aj, where 0 ≤ ij < n.

Could you do this in O(n) runtime?

Example:

Input: [3, 10, 5, 25, 2, 8]

Output: 28

Explanation: The maximum result is 5 ^ 25 = 28.

思路:按照位来算

/*
 * 异或出来的结果就是31!种
 * 实际上我们可以一个bit一个bit来,这样可以减少一点重复计算
 * 比如11....是不行的,那么11..1..就不要算了
 */
public class Solution {
    public int findMaximumXOR(int[] nums) {
    	
    	int prefix = 0, max = 0;
    	
    	for(int i=31; i>=0; i--) {
    		Set<Integer> set = new HashSet<Integer>();
    		prefix = prefix | (1<<i);
    		for(int num : nums)
    			set.add(num & prefix);
    		
    		// 计算可能的更大值,基于以下定理:a^b^b=a,
    		// 如果set里面有2个数异或可以得到possibleMax,那么possibleMax和set里的一个数异或得到的就是set里面的另外一个数
    		int possibleMax = max | (1<<i);
    		for(int num : set)
    			if(set.contains(possibleMax ^ num)) {
    				max = possibleMax;
    				break;
    			}
    	}
    	
		return max;
        
    }
}


Trie树版本

/*
 * 需要两两比较,又是按照一位一位来计算的,所以考虑Trie
 * 总体思路还是按位来算
 */
public class trie1 {
	
	class Trie {
		Trie[] children = new Trie[2];
	}
	
    public int findMaximumXOR(int[] nums) {
        
    	// build up Trie
    	Trie root = new Trie();
    	for(int num : nums) {
    		Trie cur = root;
    		for(int i=31; i>=0; i--) {
    			int bit = (num >> i) & i;
    			if(cur.children[bit] == null)
    				cur.children[bit] = new Trie();
    			cur = cur.children[bit];
    		}
    	}
    	
    	// find bit by bit
    	int max = Integer.MIN_VALUE;
    	for(int num : nums) {
    		Trie cur = root;
    		int sum = 0;
    		for(int i=31; i>=0; i--) {
    			int bit = (num >> i) & i;
    			int xor = bit ^ 1;
    			if(cur.children[xor] != null) {
    				cur = cur.children[xor];
    				sum += (1 << i);
    			} else if(cur.children[bit] != null)
    				cur = cur.children[bit];
    		}
    		max = Math.max(max, sum);
    	}
    	
    	return max;
    }
}

用Object数组表示的Trie树版本

/*
 * 新建Class Trie会超时
 */
public class Solution {
	
    public int findMaximumXOR(int[] nums) {
        
    	// build up Trie
    	Object[] root = {null, null};
    	for(int num : nums) {
    		Object[] cur = root;
    		for(int i=31; i>=0; i--) {
    			int bit = (num >> i) & 1;
    			if(cur[bit] == null)
    				cur[bit] = new Object[]{null, null};
    			cur = (Object[]) cur[bit];
    		}
    	}
    	
    	// find bit by bit
    	int max = Integer.MIN_VALUE;
    	for(int num : nums) {
    		Object[] cur = root;
    		int sum = 0;
    		for(int i=31; i>=0; i--) {
    			int bit = (num >> i) & 1;
    			int xor = bit ^ 1;
    			if(cur[xor] != null) {
    				cur = (Object[]) cur[xor];
    				sum += (1 << i);
    			} else if(cur[bit] != null)
    				cur = (Object[]) cur[bit];
    		}
    		max = Math.max(max, sum);
    	}
    	
    	return max;
    }
}


2刷:一般这样的bit运算都有个套路就是要按位来求,反正int就32位,

求到第i位时判断有没有2个数的前缀异或得到当前的最大值,想到了前缀,Trie树就自然而然想到了

/*
 * 按位来求
 * 求到第i位时判断有没有2个数的前缀异或得到当前的最大值
 */
public class Solution {
    public int findMaximumXOR(int[] nums) {
        int max = 0, prefix = 0;
        
        for(int i=31; i>=0; i--) {
        	// 把前缀放到set里面
        	prefix = prefix | (1<<i);
        	Set<Integer> s = new HashSet<Integer>();
        	for(int num : nums)		s.add(num & prefix);
        	
        	int tmp = max | (1<<i);
        	for(int num : s)
        		if(s.contains(tmp ^ num)) {	// 有2个前缀可以异或成当前可能的最大值
        			max = tmp;
        			break;
        		}
        }
        
        return max;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值