码迷,mamicode.com
首页 > 编程语言 > 详细

子数组的最大异或和---Trie

时间:2019-03-23 17:29:49      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:mat   tar   等等   star   void   nod   style   pac   nullptr   

  异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。

  前缀树详解:https://www.cnblogs.com/tianzeng/p/10584650.html

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

//1.暴力解O(n^3)
int get_max_eor(const vector<int>& arr)
{
    if(arr.empty()||arr.size()<0)
        return -1;

    int Max=-0x3f3f;
    for(unsigned int i=0;i<arr.size();++i)//以i结尾的每个子数组
    {
        for(unsigned int start=0;start<=i;++start)//0..i/1..i/2..i等等,前两个for找所有的子数组
        {
            int Eor=0;
            for(unsigned int k=start;k<=i;++k)//遍历每个区间:k=[start..i],求每个区间的最大异或和,arr.at(k)
                Eor^=(arr.at(k));
            Max=max(Max,Eor);
        }
    }
    return Max;
}

//2.记忆化优化解O(n^2)
//0...i异或结果为Sum
//0...start-1异或结果为A
//start...i的异或结果为Sum^A
int get_max_eor1(const vector<int>& arr)
{
    if(arr.size()<0||arr.empty())
        return -1;

    int Eor=0;
    int Max=-0x3f3f;
    for(unsigned int i=0;i<arr.size();++i)
    {
        Eor^=arr.at(i);//遍历0...i,Xor保存每个以i结尾的最长数组的异或和
        Max=max(Max,Eor);//一:可能是整个以i结尾的数组的异或和最大
        int res=0;
        for(unsigned int start=0;start<=i;++start)
        {
            res^=arr.at(start);//每个以i结尾的数组的前半部分
            Max=max(Max,res^Eor);//二:可能是某个子数组的异或和最大
        }
    }
    return Max;
}
//2 O(n^2)
int get_max_eor2(const vector<int>& arr)
{
    if(arr.size()<0||arr.empty())
        return -1;

    vector<int> dp(arr.size(),0);
    int Eor=0;
    int Max=-0x3f3f;
    for(unsigned int i=0;i<arr.size();++i)
    {
        Eor^=arr.at(i);
        Max=max(Max,Eor);
        for(unsigned int start=1;start<=i;++start)
        {
            int res=Eor^dp[start-1];
            Max=max(Max,res);
        }
        dp.at(i)=Eor;
    }
    return Max;
}
//3
//0...i的异或结果Eor存
//0...0异或结果 0...1的异或结果 0...2的异或结果 直到0...i-1的异或结果(装入黑盒---前缀树)
typedef struct Node
{
    Node *next[2];
    Node()
    {
        next[0]=nullptr;
        next[1]=nullptr;
    }
}Node;
class Trie
{
public:
    int get_max_eor3(const vector<int>& arr);
    ~Trie()
    {
        delete head;
    }
private:
    int max_eor(const int &num);
    void add(const int &num);
    static Node *head;
};
Node* Trie::head=new Node();

int Trie::get_max_eor3(const vector<int>& arr)
{
    if(arr.size()<0||arr.empty())
        return -1;

    int Max=-0x3f3f;
    int Eor=0;
    Trie trie;
    trie.add(0);

    for(unsigned int i=0;i<arr.size();++i)
    {
        Eor^=arr.at(i);
        Max=max(max_eor(Eor),Max);
        add(Eor);
    }
    return Max;
}

void Trie::add(const int& num)//把num添加到前缀树中
{
    Node *cur=head;
    int res=0;
    for(int move=31;move>=0;--move)
    {
        int path=((num>>move)&1);//取每一位
        cur->next[path]=(cur->next[path]==nullptr?new Node():cur->next[path]);
        cur=cur->next[path];
    }
}
//符号位尽量为0,后面的位是0走1,1走0,没得选就将就着走,尽量保持最大化值
//每次选最优,可以找到最大值
int Trie::max_eor(const int& num)//num和前缀树中的哪个值异或和最大
{
    int res=0;
    Node *cur=head;

    for(int move=31;move>=0;--move)
    {
        int path=((num>>move)&1);
        int best=(move==31?path:(path^1));
        best=(cur->next[best]!=nullptr?best:(best^1));
        res|=((path^best)<<move);
        cur=cur->next[best];
    }
    return res;
}

int main()
{
    vector<int> arr{1,2,3,5,6,8,9};
    cout<<get_max_eor(arr)<<endl;
    cout<<get_max_eor1(arr)<<endl;
    cout<<get_max_eor2(arr)<<endl;

    Trie t;
    cout<<t.get_max_eor3(arr)<<endl;
    return 0;
}

 

子数组的最大异或和---Trie

标签:mat   tar   等等   star   void   nod   style   pac   nullptr   

原文地址:https://www.cnblogs.com/tianzeng/p/10584668.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!