Find the maximum subarray XOR in a given array


Find the maximum subarray XOR in a given array - GeeksforGeeks
Given an array of integers. find the maximum XOR subarray value in given array. Expected time complexity O(n).
Examples:
Input: arr[] = {1, 2, 3, 4}
Output: 7
The subarray {3, 4} has maximum XOR value

Input: arr[] = {8, 1, 2, 12, 7, 6}
Output: 15
The subarray {1, 2, 12} has maximum XOR value

An Efficient Solution can solve the above problem in O(n) time under the assumption that integers take fixed number of bits to store. The idea is to use Trie Data Structure. Below is algorithm.
1) Create an empty Trie.  Every node of Trie is going to 
   contain two children, for 0 and 1 value of bit.
2) Initialize pre_xor = 0 and insert into the Trie.
3) Initialize result = minus infinite
4) Traverse the given array and do following for every 
   array element arr[i].
       a) pre_xor  = pre_xor  ^ arr[i]
          pre_xor now contains xor of elements from 
          arr[0] to arr[i].
       b) Query the maximum xor value ending with arr[i] 
          from Trie.
       c) Update result if the value obtained in step 
          4.b is more than current value of result.
How does 4.b work?
We can observe from above algorithm that we build a Trie that contains XOR of all prefixes of given array. To find the maximum XOR subarray ending with arr[i], there may be two cases.
i) The prefix itself has the maximum XOR value ending with arr[i]. For example if i=2 in {8, 2, 1, 12}, then the maximum subarray xor ending with arr[2] is the whole prefix.
ii) We need to remove some prefix (ending at index from 0 to i-1). For example if i=3 in {8, 2, 1, 12}, then the maximum subarray xor ending with arr[3] starts with arr[1] and we need to remove arr[0].
To find the prefix to be removed, we find the entry in Trie that has maximum XOR value with current prefix. If we do XOR of such previous prefix with current prefix, we get the maximum XOR value ending with arr[i].
If there is no prefix to be removed (case i), then we return 0 (that’s why we inserted 0 in Trie).
    // Assumed int size
    static final int INT_SIZE = 32;
       
    // A Trie Node
    static class TrieNode
    {
        int value;  // Only used in leaf nodes
        TrieNode[] arr =  new TrieNode[2];
        public TrieNode() {
            value = 0;
            arr[0] = null;
            arr[1] = null;
        }
    }
    static TrieNode root;
      
    // Inserts pre_xor to trie with given root
    static void insert(int pre_xor)
    {
        TrieNode temp = root;
       
        // Start from the msb, insert all bits of
        // pre_xor into Trie
        for (int i=INT_SIZE-1; i>=0; i--)
        {
            // Find current bit in given prefix
            int val = (pre_xor & (1<<i)) >=1 ? 1 : 0;
       
            // Create a new node if needed
            if (temp.arr[val] == null)
                temp.arr[val] = new TrieNode();
       
            temp = temp.arr[val];
        }
       
        // Store value at leaf node
        temp.value = pre_xor;
    }
       
    // Finds the maximum XOR ending with last number in
    // prefix XOR 'pre_xor' and returns the XOR of this 
    // maximum with pre_xor which is maximum XOR ending 
    // with last element of pre_xor.
    static int query(int pre_xor)
    {
        TrieNode temp = root;
        for (int i=INT_SIZE-1; i>=0; i--)
        {
            // Find current bit in given prefix
            int val = (pre_xor & (1<<i)) >= 1 ? 1 : 0;
       
            // Traverse Trie, first look for a
            // prefix that has opposite bit
            if (temp.arr[1-val] != null)
                temp = temp.arr[1-val];
       
            // If there is no prefix with opposite
            // bit, then look for same bit.
            else if (temp.arr[val] != null)
                temp = temp.arr[val];
        }
        return pre_xor^(temp.value);
    }
       
    // Returns maximum XOR value of a subarray in 
        // arr[0..n-1]
    static int maxSubarrayXOR(int arr[], int n)
    {
        // Create a Trie and insert 0 into it
        root = new TrieNode();
        insert(0);
       
        // Initialize answer and xor of current prefix
        int result = Integer.MIN_VALUE;
        int pre_xor =0;
       
        // Traverse all input array element
        for (int i=0; i<n; i++)
        {
            // update current prefix xor and insert it 
                // into Trie
            pre_xor = pre_xor^arr[i];
            insert(pre_xor);
       
            // Query for current prefix xor in Trie and 
            // update result if required
            result = Math.max(result, query(pre_xor));
  
        }
        return result;
    }
https://www.cnblogs.com/1pha/p/8721373.html
假设答案区间为 [L, R], 则答案为 XOR[L, R], 可以将区间分解为 XOR[L,R] == XOR[0, L - 1] ^ XOR[L, R],
因此
  1. 不断更新所以数字的 前缀异或和, 将每一个前缀异或和 都 保存到 01Trie 中
  2. 在 01Trie 中查询与它 异或值最大 的 前缀异或和
  3. 根据 Step2 的结果, 更新 ans. 重复第一步, 直至无剩余元素.
需要注意的是, 对于样例中的 3 8 2 6 4 的 前缀异或和分别 为 3 11 9 15 11, 最大值为15, 区间为 [0, 4), 因此每个Trie的初始状态应存在 0.
struct BinTrie { BinTrie* next[2]; BinTrie() { next[0] = next[1] = NULL; } }; void insertNum(BinTrie* root, unsigned num) { BinTrie* p = root; for(int i = 31; i >= 0; i--) { int index = (num >> i) & 1; if(!p->next[index]) p->next[index] = new BinTrie(); p = p->next[index]; } } unsigned queryDiff(BinTrie* root, unsigned num) { num = ~num; BinTrie* p = root; unsigned ret = 0; for(int i = 31; i >= 0; i--) { int index = (num >> i) & 1; if(!p->next[index]) index = 1 - index; ret += (index << i); p = p->next[index]; } return ret; } int main() { int nTest; scanf("%d", &nTest); while(nTest--) { int nNum; scanf("%d", &nNum); unsigned pre = 0, ans = 0; BinTrie* root = new BinTrie(); // 保证了 [0, x) 区间的合理性 // 否则对于 15 来说, Trie中最大不同的前缀异或和 queryDiff(root, pre) 并不为 0 insertNum(root, 0); while(nNum--) { unsigned num; scanf("%u", &num); pre = pre ^ num; insertNum(root, pre); ans = max(ans, queryDiff(root, pre) ^ pre); } printf("%u\n", ans); } return 0; }
https://blog.csdn.net/u010232171/article/details/49685523
另一种方法是“后缀数组+Trie字典树+贪心算法”。

后缀数组
定义preXori=A1xorA2xor...xorAipreXori=A1xorA2xor...xorAi,那么数组AA内任意子数组的异或和如下
resi,j=preXorixorpreXorj,i<=j
resi,j=preXorixorpreXorj,i<=j

因此,我们需要找到数组AA内所有的后缀子数组的异或和。然后,利用前面的数据,计算每个以AiAi结束的异或和的最大值。
Trie字典树
为了方便寻找合适的后缀数组异或和,利用Trie字典存储每个后缀数组异或和preXoripreXori。preXoripreXori以二进制(01)的形式存储到Trie中,因此该Trie也称为”01”字典树。从Trie的根往叶子节点的方向对应二进制preXoripreXori的高位到低位。例如preXori=(5)10=(101)2preXori=(5)10=(101)2,左数第一个1是高位,第二个1是低位。

该链接是一道Tire树的联系题:
http://blog.csdn.net/u010232171/article/details/43373697

贪心算法
完成上面两步后,开始计算以AiAi结束子数组的最大异或和。思路是用已知的preXori=A1xorA2...xorAipreXori=A1xorA2...xorAi作为Trie树的查询值。在查询过程中,力求找到与该值异或结果最大的值。遵循优先寻找对应二进制位上不同的节点(异或运算的特点1xor0=11xor0=1)。这样,高位趋近1,结果就是最大的。

https://shanzi.gitbooks.io/algorithm-notes/problem_solutions/max_xor_sub_sequence.html
https://github.com/cherryljr/NowCoder/blob/master/Find%20the%20Maximum%20Subarray%20XOR%20in%20an%20Array.java
 * Approach: Trie 对于 Subarray 问题,我们可以考虑 PreSum, Two Pointer, DP 等方法,
 * 经过分析,我们发现也就只有 PreXOR(EOR) 的方法可以用一用。 总体思路为:求所有以 i 作为结尾的 最大异或 子数组。那么答案必定在这里面。
 * 但是我们发现在本题中无法利用 HashMap 实现加速。(因为我们没办法通过它来求得 最大异或和)
 * 因此我们需要考虑另外的一种数据机构来帮我们实现加速。而这里使用的就是 Trie Tree.
 *
 * 我们在 Trie Tree 中放入了放入了 从0到i 的异或值 EOR. 那么根据 异或运算 的性质: A^B=C => B^C=A 我们可以通过
 * 0...i 的异或和计算出 任意 j...i 的异或值: XOR[j...i] = XOR[0...i] ^ XOR[0...j-1]
 *
 * 那么Trie如何实现快速得到 异或后的最大值 呢?(本题的核心部分) 我们是按照这样的策略(其实是一个贪心的做法): 对于一个 int 类型,总共有 32
 * 位。因此我们 Trie Tree 的高度为 32. 当我们想要查询如何获得最大的异或值时, 我们可以 从高位开始 向低位逐位查找 最佳异或值。遵循着
 * 首先满足高位 的做法依次向下查询。 同时:我们还需要注意符号位,这里比较特殊,因为 0 代表正,1代表负。 所以对于 符号位 我们要取与原来位置上 相同
 * 的数, 而对于其他位我们要去与原来位置上 不同的数(异或1后的数)。 如果 取不到 最佳值的话,我们就只能取现有的值了(总共就两个...)
 * 最后假设我们得到的 最大异或和 为:EOR[x]^EOR[y],那么就说明 最大异或和子数组为:[x+1...y] 这样查找下来我们需要循环 32
 * 次,时间复杂度为 O(1) 而我们需要查找 n 个数,因此总体时间复杂度为 O(n)
 */
  public int maxSubarrayXOR(int[] nums) {
    if (nums == null || nums.length == 0) {
      return 0;
    }

    Trie trie = new Trie();
    // 初始化 trie,将 0 将入到 trie 中,因为 X^0=X
    trie.add(0);
    int eor = 0;
    int max = Integer.MIN_VALUE;
    for (int i = 0; i < nums.length; i++) {
      eor ^= nums[i];
      // 在 Trie 中寻找与 eor 异或起来最大的元素,返回异或之后的结果
      max = Math.max(max, trie.maxXOR(eor));
      // 将 eor 加入到 Trie Tree 中
      trie.add(eor);
    }

    return max;
  }

  class TrieNode {
    // Trie Tree 的节点,因为是 2进制,所以我们只需要 0,1 两个节点即可
    TrieNode[] child;

    TrieNode() {
      child = new TrieNode[2];
    }
  }

  class Trie {
    TrieNode root;

    Trie() {
      root = new TrieNode();
    }

    // 将 nums[i] 加入到 Trie Tree 中
    public void add(int num) {
      TrieNode curr = root;
      for (int i = 31; i >= 0; i--) {
        int path = ((num >> i) & 1); // 获得第 i 位上的值
        if (curr.child[path] == null) {
          curr.child[path] = new TrieNode();
        }
        curr = curr.child[path];
      }
    }

    public int maxXOR(int num) {
      TrieNode curr = root;
      int rst = 0;
      for (int i = 31; i >= 0; i--) {
        // 获得第 i 位上的值
        int path = ((num >> i) & 1);
        // 根据 path,我们需要得到相应的最佳 异或值
        // 注意:如果是 符号位 的话,我们取与path相同的值,否则取与 path 不同的值
        int best = i == 31 ? path : (path ^ 1);
        // 判断 curr.child[best] 节点是否存在,存在的话我们就能取到最佳值
        // 否则只能取另外一个值了
        best = curr.child[best] != null ? best : (best ^ 1);
        // 将 rst 的第 i 位置为 path^best
        rst |= ((path ^ best) << i);
        curr = curr.child[best];
      }
      return rst;
    }

  }
https://www.quora.com/How-do-I-find-a-subarray-with-maximum-xor



Suppose you need to find two numbers in an array with maximum XOR. We store the binary representation of every element of the array in trie. Now, for every element in the array, we traverse the trie to find the maximum XOR we can obtain using the element and the elements stored in the trie. The traversal of trie attempts to make the most significant bit 1. The time complexity of this algorithm would be n*(log2(MAX)), where MAX is the maximum element in the array.
For finding the subarray we follow a similar approach. Let us say the subarray with maximum XOR is F(L,R) where L and R are the left and right index of the subarray. Observe that F(L,R) = F(1,L-1) XOR F(1,R) because XOR of two same numbers is 0. So, XOR of F(1,L-1) and F(1,R) would be XOR of only the elements between L and R.
Now, insert in trie F(1,i) for all 1<=i<=n then, all we need to do is find two elements in this trie whose XOR is maximum, which is the problem we discussed above.



Simple Solution is to use two loops to find XOR of all subarrays and return the maximum.
int maxSubarrayXOR(int arr[], int n)
{
    int ans = INT_MIN;     // Initialize result
    // Pick starting points of subarrays
    for (int i=0; i<n; i++)
    {
        int curr_xor = 0; // to store xor of current subarray
        // Pick ending points of subarrays starting with i
        for (int j=i; j<n; j++)
        {
            curr_xor = curr_xor ^ arr[j];
            ans = max(ans, curr_xor);
        }
    }
    return ans;
}


https://www.geeksforgeeks.org/find-maximum-xor-value-sub-array-size-k/
Given an array of integers, the task is to find maximum XOR value of a subarray of size K.
Examples :
Input  : arr[] = {2, 5, 8 ,1 , 1 ,3} k = 3
Output : 15
Explanation : All subrrays of size k (=3) and
              their XOR values are:
 {2, 5, 8} => XOR value =  15
 {5, 8, 1} => XOR value =  12
 {8, 1, 1} => XOR value =  8
 {1, 1, 3} => XOR value =  3
Maximum of all XOR values = 15
An efficient solution takes O(n) time. The idea is simple, we can find XOR value of current subarray of size k by removing first element of previous subarray and adding last element of current subarray. We can remove an element from current XOR by doing XOR of it again because of property of XOR that a ^ x ^ x = a.

    // Returns maximum XOR value of subarray of size k
    static int maximumXOR(int arr[] , int n , int k)
    {
          
        // Compute XOR value of first subarray of size k
        int current_xor = 0 ;
        for (int i = 0 ; i < k ; i++)
            current_xor = current_xor ^ arr[i];
      
        // Traverse rest of the array
        int max_xor = current_xor;
          
        for (int i = k ; i < n; i++)
        {
              
            // First remove previous subarray's first
            // element
            current_xor = current_xor ^ arr[i-k];
      
            // add new element
            current_xor = current_xor ^ arr[i];
      
            // Update maximum xor value
            max_xor = Math.max(max_xor, current_xor);
        }
      
        return max_xor;
    }

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts