MENU

给定一个数组,求子数组的最大异或和

August 21, 2018 • Read: 3939 • 算法阅读设置

直接说这道题时间复杂度 O (n) 的做法,构建前缀树。假设将 0-0、0-1、0-2、...、0-i-1 的异或结果全部装在前缀树中,那么以 i 结尾的最大异或和就是 0 到某一位置 x 的异或结果和 i 异或结果最大,举个例子,假设 x 是 3,0-3 的异或结果和 i 进行异或得到的结果最大,那么就说明 4-i 的异或结果是最大的。

但是如何知道 x 到底是多少,换句话说,0-x 中哪个值和 i 进行异或得到的结果最大。其实这个也比较好想,假设 i 是 0100(最高位 0 是符号位),只需要沿着前缀树找到 0011,异或出来的结果就是 0111,一定就是最大的,如果不能刚好找到合适的,那就有什么选什么,只要保证从最高位开始往下每次的决策是最优的就行

有一种特殊情况,假设 i 还是 0100,但是此时前缀树中最高位只有 1,没有 0,那么最高位得出的异或结果永远是负数,后面的位应该如何选?其实也是按照最优决策去选,假设异或结果是 1111,那么转换为十进制就是 - 1,绝对没有比这还大的负数了

  • public class Main {
  • public static class Node {
  • public Node[] nexts = new Node[2]; // 0,1
  • }
  • public static class NumTrie {
  • public Node head = new Node();
  • public void add(int num) {
  • Node cur = head;
  • for(int move = 31;move >= 0;move--) {
  • int path = ((num >> move) & 1);//每一位上的数字(0,1)
  • cur.nexts[path] = (cur.nexts[path] == null ? new Node() : cur.nexts[path]);
  • cur = cur.nexts[path];
  • }
  • }
  • public int maxXor(int num) {//num=0~i的异或结果
  • Node cur = head;
  • int res = 0;
  • for(int move = 31;move >= 0;move--) {
  • int path = (num >> move) & 1;//提取每一位
  • int best = (move == 31 ? path : (path ^ 1));//最高位期望一样,非最高位期望相反
  • best = cur.nexts[best] != null ? best : (best ^ 1);//实际要选的路(如果没有期待选的路)
  • res |= (path ^ best) << move;//设置答案的每一位
  • cur = cur.nexts[best];//继续往下走
  • }
  • return res;
  • }
  • }
  • public static int maxXorSubArray(int[] arr) {
  • if (arr == null || arr.length == 0)
  • return 0;
  • int max = Integer.MIN_VALUE;
  • int xor = 0;
  • NumTrie numTrie = new NumTrie();
  • numTrie.add(0);
  • for(int i = 0;i < arr.length;i++) {
  • xor ^= arr[i];
  • max = Math.max(max,numTrie.maxXor(xor));
  • numTrie.add(xor);
  • }
  • return max;
  • }
  • }
Last Modified: November 2, 2018
Archives Tip
QR Code for this page
Tipping QR Code