狗东二面算法笔试:给出了一个整数数组从前到后两两元素的与或结果的数组,求出原始数组,做出一半

本文介绍了一种通过异或操作逆向还原原始整数数组的方法。针对长度为n的数组,其元素为1到n的不同整数,给出了由两两元素异或结果组成的数组,详细解释了如何重构原始数组。重点讨论了数组长度为奇数和偶数时的不同处理策略。

假设有一个长度n的整数数组,数组中元素分别是从1到n满布的正整数,元素顺序任意组合。现在给出这个数组的从前到后两两元素进行与或^的结果的一个数组,让求出原始数组。函数签名:vector<int> getOriginArr(vector<int> xor_vec,int n);

解:与或是指只当对应位一个是0另一个是1时才得到1,否则得到0;即0^0=0;1^1=0;0^1=1;1^0=1;与或的特性是:1、一个数字A与自身与或的结果为0;2、0与任何数字与或的结果都是那个数字本身,即0^A=A;

对原始数组[a,b,c,d,e],给出的两两与或结果数组是xor_vec=[a^b,b^c,c^d,d^e],让反算出原始数组[a,b,c,d,e]。利用与或的特性,知道了满布的原始数组的区间是从1到n,那a^b^c^d^e=m(已知)可以自己算出来,然后对与或结果数组[a^b,b^c,c^d,d^e],可以得到(a^b)^(c^d)=xor_vec[0]^xor_vec[2],与a^b^c^d^e=m联立可得:(a^b)^(c^d)^(a^b^c^d^e)=e=xor_vec[0]^xor_vec[2]^m从而可以求出e,然后对xor_vec最后一项d^e=xor_vec[xor_vec.size()-1],最后一个元素e已经知道了,那等式左右同时异或一个e得到:e^d^e=d=xor_vec[xor_vec.size()-1]^e,右式已知。倒数第二个数d知道后对xor_vec倒数第二项c^d=xor_vec[xor_vec.size()-1-1],左右同时异或一个d得到:d^c^d=c=xor_vec[xor_vec.size()-1-1]^d,右式已知,,,,倒序向前,能求出所有元素来。

代码:

//京东异或
std::vector<int> getPermutation(const std::vector<int> &xor_vec,int n){
    //列个简单式子吧,再不要盯着已知示例懵逼了:
    /*
        如果是奇数长度的数组[a,b,c,d,e],从前到后两两异或的输入数组就是xor_vec=[a^b,b^c,c^d,d^e],
        此时可以组合得到(a^b)^(c^d)=xor_vec[0]^xor_vec[2],根据a^b^c^d^e=1^2^...^n-1^n=m(已知)
        可以求出e=xor_vec[0]^xor_vec[2]^m,得到最后一个元素后根据两两异或的结果从后往前就能一一求出原始
        数组元素。后者从后往前组合得到(d^e)^(b^c)=xor_vec[3]^xor_vec[1],根据a^b^c^d^e=1^2^...^n-1^n=m(已知)
        可以求出a=xor_vec[3]^xor_vec[1]^m,得到第一个元素后根据两两异或的记过从前往后就能一一求出原始数组
        元素
        如果是偶数长度的数组[a,b,c,d],从前到后两两异或的输入数组xor_vec=[a^b,b^c,c^d],
        此时无法组合出只排除一个元素的异或结果,
    */
   std::vector<int> res(xor_vec.size()+1,0);   //1到n满布
   if(xor_vec.size()%2==0){ //偶数的情况
        //首先根据题意算出1到n满布元素的异或结果:
        int xor_all(0); //0与任何数异或都得到那个数本身,所以这里默认值用0可以,或者xor_all初始为1,然后从2开始异或
        for(int i(1);i<=n;i++)  xor_all^=i;
        //针对xor_vec从头到尾隔一个结果组合
        int xor_pre(0);
        for(int i(0);i<xor_vec.size();i+=2) xor_pre^=xor_vec[i];

        
        int ilast(res.size()-1);    //倒着填res的下标
        res[ilast--]=xor_pre^xor_all;
        //然后倒着求前面元素
        for( int i(xor_vec.size()-1);i>=0;i--){
            res[ilast]=xor_vec[i]^res[ilast+1];
            ilast--;
        }
   }
   return res;
} 

测试:

int main(int argc,char *argv[]){
    int arr2[]={3,1,4,5,9,2,6,8,7};
    std::vector<int> ori_vec(9,0);
    for(int i(0);i<9;i++) ori_vec[i]=arr2[i];
    std::vector<int> xor_vec(ori_vec.size()-1,0);
    for(int i(0);i<ori_vec.size()-1;i++) xor_vec[i]=ori_vec[i]^ori_vec[i+1];
    for(int & rele:xor_vec)std::cout<<rele<<"\t";
    //2       5       1       12      11      4       14      15
    std::cout<<"\n";
    std::vector<int> res;
    res=getPermutation(xor_vec,9);
    for(int & rele:res)std::cout<<rele<<"\t";
    //3       1       4       5       9       2       6       8       7
    std::cout<<"\n";
}

这是车祸现场,至今难忘,紧张都不是事,关键是要思考,思考起来就没时间紧张了,什么是未知量什么是已知量、画个图、列个式子、举个小规模的例子、找规律。我甚至犯了高中时的错,盯着给出的示例都不清楚谁求谁了(口述题,当时我甚至忘记还有个条件是原始数组1到n满布,压根没想到1^2^2^...^n),高中毕业多少年了,还是一紧张就抽抽、就迷糊、就完蛋,阿西吧。

http://collabedit.com/5dmpr

#include<iostream>
/*

*/
int main(int argc,char *argv[]){
    std::cout<<"hello\n";
}

1, 2, 3, ... n

permutation (1,3,2,5,6,4), (1,2,3,4,5,6)
XOR: n - 1 numbers
i, --> i, i + 1

XOR vector (n - 1) --> permutation (n)

1.
(3, 1)
(1, 2, 3) --> XOR (3, 1)

2. 
(6, 5, 4, 6)
(2, 4, 1, 5, 3)


a
a ^ a = ?

1) the XOR result of n numbers
2) combination: n - 1

// n % 2 == 1
vector<int> getPermutation(const vector<int>& xor_vec, int n) {
// your code here
    //1~n数字
    //int n(-1*(1<<30));
    //for(int & rele:xor_vec) n=rele>n?rele:n;
    int xorAll(0);
    for(int i(1);i<=n;i++) xorAll^=i;
    vector<int> arr(xor_vec.size()+1,0);
    int ilast(arr.size()-1);
    //先求最后一个数组,把xor_vec除最后一个
    //先考虑输入xor_vec偶数情况
    if(xor_vec.size()%2==0){
        int pre_xor(0);
        for(int i(0);i<=xor_vec.size()-1;i+=2){
            pre_xor^=xor_vec[i];
        }
        //最后一个数
        arr[ilast--]=pre_xor^xorAll;
        //然后倒着找前面一个数
        for(int i(xor_vec.size()-1);i>=0;i--){
            arr[ilast]=arr[ilast+1]^xor_vec[i];
            ilast--;
        }
        //arr都求出来了
        return arr;
    }
}
int main(int argc,char *argv[]){
    int arr[]={6,5,4,6};
    vector<int> xor_vec;
    for(int i(0);i<4;i++) xor_vec.push_back(arr[i]);
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值