数组异或和的定义:把数组中所有的数异或起来得到的值。给定一个整型数组arr,其中可能有正、有负,有零,求其中子数组的最大异或和。
输出包含两行,第一行一个整数n,代表数组arr长度,第二个n个整数,代表数组arr
。
输出一个整数,代表其中子数组的最大异或和。
4 3 -28 -29 2
7
{-28,-29}这个子数组的异或和为7,是所有子数组中最大的 时间复杂度,额外空间复杂度
。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
typedef struct tn {
struct tn **children; // 存放子节点的指针
} node;
node *new_node() {
node *new_node = malloc(sizeof(node));
new_node->children = (node **) calloc(2, sizeof(node *));
return new_node;
}
void destroy_node(node *node) {
free(node->children);
free(node);
}
void destroy_whole_path(node *node) {
destroy_node(node->children[0]);
destroy_node(node->children[1]);
destroy_node(node);
}
void insert(node *root, int num) {
node *cur = root;
int path;
for (int move = 31; move >= 0; move--) {
path = (num >> move) & 1;
if (cur->children[path] == NULL) {
cur->children[path] = new_node();
}
cur = cur->children[path];
}
}
int max_eor(node *root, int eor) {
node *cur = root;
int max = 0, path, best;
for (int move = 31; move >= 0; move--) {
path = (eor >> move) & 1;
best = move == 31 ? path : (path ^ 1);
best = cur->children[best] == NULL ? (best ^ 1) : best;
max = max << 1 | (path ^ best);
cur = cur->children[best];
}
return max;
}
int main(void) {
int n, *arr, ans = INT_MIN;
scanf("%d", &n);
arr = (int *) malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
scanf("%d", arr + i);
}
int eor = 0;
node *root = new_node();
insert(root, 0);
for (int i = 0; i < n; i++) {
eor ^= arr[i];
ans = MAX(ans, max_eor(root, eor));
insert(root, eor);
}
printf("%d\n", ans);
destroy_whole_path(root);
free(arr);
return 0;
} #include<iostream>
#include<vector>
using namespace std;
void add(int newNum);
int maxXor(int eorj);
int maxXorSubarray2(vector<int> &arr);
class Node {
public:
Node *nexts[2] = {NULL};
};
Node *head = new Node();
void add(int newNum) {
Node *cur = head;
for (int move = 31; move >= 0; move--) {
int path = ((newNum >> move) & 1);
cur->nexts[path] = cur->nexts[path] == NULL ? new Node() : cur->nexts[path];
cur = cur->nexts[path];
}
}
int maxXor(int eorj) {
Node *cur = head;
int res = 0;
for (int move = 31; move >= 0; move--) {
int path = (eorj >> 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;
}
int maxXorSubarray2(vector<int> &arr) {
if (arr.empty() || arr.size() == 0) {
return 0;
}
int mx = INT32_MIN;
int eor = 0;
add(0);
for (int j = 0; j < arr.size(); j++) {
eor ^= arr[j];
mx = max(mx, maxXor(eor));
add(eor);
}
return mx;
}
int main() {
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
int res = maxXorSubarray2(arr);
cout << res << endl;
return 0;
} import java.util.Scanner;
class Node {
public Node[] next = new Node[2]; // 每个节点表示整数的一个位,有0和1两个状态
}
class NumTrie {
public Node head = new Node();
public void add(int num) {
Node cur = head;
for(int move = 31; move >= 0; move--){
int bit = (num >> move) & 1; // 取出从右往左的第move位
cur.next[bit] = cur.next[bit] == null? new Node(): cur.next[bit];
cur = cur.next[bit];
}
}
public int maxXOR(int num) {
Node cur = head;
int res = 0;
for(int move = 31; move >= 0; move--){
int bit = (num >> move) & 1;
int expect = move == 31? bit: bit ^ 1; // 当前位为符号位时,希望要走的路径与当前位相同
expect = cur.next[expect] == null? expect ^ 1: expect; // 期望路径不空才能走
res |= (bit ^ expect) << move; // 把res中这一位的状态改了
cur = cur.next[expect];
}
return res;
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int max = Integer.MIN_VALUE;
int eor = 0; // 前缀异或和
NumTrie trie = new NumTrie();
trie.add(0);
for(int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
eor ^= arr[i];
max = Math.max(max, trie.maxXOR(eor)); // 找到数组以arr[i]结尾时,最大的异或和
trie.add(eor);
}
System.out.println(max);
}
} import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
class Node {
public Node[] nodes;
public Node() {
nodes = new Node[2];
}
}
class PrefixTree {
public Node head;
public PrefixTree() {
this.head = new Node();
}
public void add(int eor) {
Node cur = head;
for (int move = 31; move >= 0; move--) {
int i = (eor >> move) & 1;
if (null == cur.nodes[i]) {
cur.nodes[i] = new Node();
cur = cur.nodes[i];
} else {
cur = cur.nodes[i];
}
}
}
public int max(int eor) {
int res = 0;
Node cur = head;
for (int move = 31; move >= 0; move--) {
int i = (eor >> move) & 1;
int best;
if (move == 31) {
best = i;
} else {
best = i ^ 1;
}
if (cur.nodes[best] == null) {
best = best ^ 1;
cur = cur.nodes[best];
} else {
cur = cur.nodes[best];
}
res |= best << move;
}
return res ^ eor;
}
}
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine());
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(reader.readLine());
}
int eor = 0;
PrefixTree tree = new PrefixTree();
tree.add(0);
int max = Integer.MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
eor = eor ^ arr[i];
max = Math.max(max, tree.max(eor));
tree.add(eor);
}
System.out.println(max);
}
} import java.util.*;
public class Main {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
System.out.println(getMaxSum(arr));
}
/*
//O(N^2)
public static int getSum(int[] arr) {
if (arr == null || arr.length == 0)
return 0;
//eor[i]的含义为arr[0...i]的异或和,只遍历arr一遍就可以生成eor数组
int[] eor = new int[arr.length];
eor[0] = arr[0];
for (int i = 1; i < arr.length; i++) {
eor[i] = eor[i-1] ^ arr[i];
}
int max = Integer.MIN_VALUE;
//因为xor[0...j] = xor[0...i-1] ^ xor[i...j]
//所以xor[i...j] = xor[0...i-1] ^ xor[0...j]
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i <= j; i++) {
max = Math.max(max, i == 0 ? eor[j] : eor[j]^eor[i-1]);
}
}
return max;
}*/
//O(N)
/*
此方法最大的优势在于可以直接得到当以j为止结尾时xor[j]的最大值,
即通过从二进制最高位开始,尽可能的让更高位异或后的结果变1,
相当于每一位上找之前结果eor[0]...eor[j-1]在此位置上有没有异或的可能,
如果没有就将就了,如果有,就把1安在当前二进制数位上,最终以O(1)的代价获得
以j位置结尾的最大异或和,然后遍历n个数,比较以每个位置为结尾的最大异或和,得到结果
*/
public static int getMaxSum (int[] arr) {
if (arr == null || arr.length == 0)
return 0;
int max = Integer.MIN_VALUE;
int eor = 0;
NumTrie trie = new NumTrie();
//为了当最大子数组只有一个数本身时,得到正确结果
trie.add(0);
for (int j = 0; j < arr.length; j++) {
//因为xor[0...j] = xor[0...i-1] ^ xor[i...j]
//所以xor[i...j] = xor[0...i-1] ^ xor[0...j]
eor ^= arr[j];
max = Math.max(max, trie.maxXor(eor));
trie.add(eor);
}
return max;
}
}
//把上面方法中eor[0...i]转变成前缀树结构
//二进制只有两种形式,所以每个节点下面最多只有两个node
class Node {
public Node[] nexts;
public Node() {
nexts = new Node[2];
}
}
class NumTrie {
public Node head = new Node();
//把某个数字加入前缀树中
//num是一个32位的整数,所以加入过程一共走32步
public void add (int num) {
Node cur = head;
for (int move = 31; move >= 0; move--) {
//从最高位到最低位获得每一位上的数
int path = (num >> move) & 1;
cur.nexts[path] = cur.nexts[path] == null ? new Node() : cur.nexts[path];
cur = cur.nexts[path];
}
}
public int maxXor(int eorj) {
Node cur = head;
int res = 0;
for (int move = 31; move >= 0; move--) {
//从最高位到最低位获得每一位上的数
int path = (eorj >> move) & 1;
//最高位上我们为了保证结果最大,当选取正数
//如果当前eor[j]为负,即最高位为1,那么我们要走的路径也要是1
//反之如果eor[j]为负,便走0,
//其他情况下尽可能走向相反的数,因为这样下来从高到低才有可能有更多的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;
}
}