程序员代码面试指南刷题--第五章.子数组的最大异或和

题目描述
数组异或和的定义:把数组中所有的数异或起来得到的值。给定一个整型数组arr,其中可能有正、有负,有零,求其中子数组的最大异或和。
输入描述:

输出包含两行,第一行一个整数n,代表数组arr长度,第二个n个整数,代表数组arr。

输出描述:

输出一个整数,代表其中子数组的最大异或和。

示例1

输入

4
3 -28 -29 2

输出

7

说明

{-28-29}这个子数组的异或和为7,是所有子数组中最大的

解法一:超时

另外用BufferedReader读数据报越界

import java.io.*;
import java.util.*;
public class Main{
    public static void main(String[] args)throws Exception{
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        // String[] seqStrArr = in.readLine().split(" ");
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
        }
        System.out.println(getRes(arr));

    }
    public static int getRes(int[] arr){
        if(arr==null||arr.length==0){
            return 0;
        }
        int[] eor=new int[arr.length];
        eor[0]=arr[0];
 
        //生成eor数组
        for(int i=1;i<arr.length;i++){
            eor[i]=eor[i-1]^arr[i];
        }
        int max=Integer.MIN_VALUE;
        for(int j=0;j<arr.length;j++){
            //j结尾
            for(int i=0;i<=j;i++){
                max=Math.max(max,i==0?eor[j]:eor[j]^eor[i-1]);
            }
        }
        return max;
    }
}

解法二:利用字典树

import java.io.*;
import java.util.*;
public class Main{
    public static void main(String[] args)throws Exception{
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        // String[] seqStrArr = in.readLine().split(" ");
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
        }
        System.out.println(getRes(arr));
    }
    public static int getRes(int[] arr){
        if(arr==null||arr.length==0) return 0;
        Trie root = new Trie();
        root.add(0);
        int max = Integer.MIN_VALUE;
        int pre = 0;
        for(int i=0;i<arr.length;i++){
            pre = pre^arr[i];
            max = Math.max(root.getMax(pre),max);
            root.add(pre);
        }
        return max;
    }
}
class TrieNode{
    public TrieNode[] map = new TrieNode[2];
}
class Trie{
    private TrieNode root = new TrieNode();
    //构建字典树
    public void add(int num){
        TrieNode node = root;
        for(int i=31;i>=0;i--){
            int path = ((num>>i)&1);
            if(node.map[path]==null){
                node.map[path] = new TrieNode();
            }
            node = node.map[path];
        }
    }
    //求此时最优解
    public int getMax(int val) {
        TrieNode curNode = root;
        int path = 0;
         
        // 最佳路径为哪条
        int best = 0;
        int res = 0;
         
        // val在前缀树中行进,一位一位地处理,得到最大异或和
        for (int move = 31; move >= 0; move--) {
            // val中该处理的那一位
            path = (val >> move) & 1;
             
            // 前缀树中理想最佳路径
            best = move == 31 ? path : (path ^ 1);
             
            // 前缀树中实际最佳路径,即res的二进制表示中这一位该取何值
            best = curNode.map[best] != null ? best : (best ^ 1);
             
            // 用或操作收集每一位产生的结果
            res |= (path ^ best) << move;
            curNode = curNode.map[best];
        }
         
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
求1~n数组最大异或和也可以使用类似于求一段区间最大异或和的方法。具体步骤如下: 1. 将1~n数组中的所有数以二进制形式插入到字典树中。 2. 对于每个数,从高位到低位依次匹配字典树上的节点,如果当前位为1,就往字典树的右树走,否则就往左树走。匹配完整个二进制数后,我们可以得到一个最大异或。 3. 对于1~n数组,我们可以将其中的相邻两个数看作一段区间,然后使用类似于求一段区间最大异或和的方法求出最大异或和。 时间复杂度为O(nlogC),其中n为数组长度,C为数的范围。以下是求1~n数组最大异或和的C++代码: ```c++ #include <iostream> using namespace std; const int MAXN = 100010; const int MAXBITS = 30; struct TrieNode { int cnt; int children[2]; } trie[MAXN * MAXBITS]; int root, node_cnt; void insert(int x) { int p = root; for (int i = MAXBITS - 1; i >= 0; i--) { int idx = (x >> i) & 1; if (!trie[p].children[idx]) { trie[p].children[idx] = ++node_cnt; } p = trie[p].children[idx]; trie[p].cnt++; } } int query(int x) { int p = root, res = 0; for (int i = MAXBITS - 1; i >= 0; i--) { int idx = (x >> i) & 1; if (trie[trie[p].children[idx ^ 1]].cnt > 0) { res += (1 << i); p = trie[p].children[idx ^ 1]; } else { p = trie[p].children[idx]; } } return res; } int main() { int n; cin >> n; root = 1; node_cnt = 1; int pre = 0, ans = 0; for (int i = 1; i <= n; i++) { int x; cin >> x; insert(pre); pre ^= x; ans = max(ans, query(pre)); } cout << ans << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值