数组异或操作

这道题出自LeetCode,题目如下:

给你两个整数,nstart

数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length

请返回 nums 中所有元素按位异或(XOR)后得到的结果。

示例 1:

输入:n = 5, start = 0
输出:8
解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。
"^" 为按位异或 XOR 运算符。

示例 2:

输入:n = 4, start = 3
输出:8
解释:数组 nums 为 [3, 5, 7, 9],其中 (3 ^ 5 ^ 7 ^ 9) = 8.

示例 3:

输入:n = 1, start = 7
输出:7

示例 4:

输入:n = 10, start = 5
输出:2

这题其实利用到了一个数学公式,即:

\[4i \oplus (4i + 1) \oplus (4i + 2) \oplus (4i + 3) = 0 \]

这个公式的推导也很简单,首先4i用二进制肯定可以表示为:

\[4i = (xxxxx00)_2 \]

类似地,其他3个数有:

\[4i + 1 = (xxxxx01)_2 \]

\[4i + 2 = (xxxxx10)_2 \]

\[4i + 3 = (xxxxx11)_2 \]

显然这4个数用二进制表示的位数是相同的,这里假设为n,那么前n-2位的表示也是完全相同的,因此4个数前n-2位异或之后的结果为0,而后两位分别为00,01,10,11,异或之后的结果也为0,所以最终得到的结果是0。

再回到题目,就是求:

\[s \oplus (s + 2) \oplus ... \oplus (s + 2(n - 1)) \]

如果s为偶数,则可以直接提取2出来,得到:

\[2(\frac{s}{2} \oplus (\frac{s}{2} + 1) \oplus ... \oplus (\frac{s}{2} + n - 1)) \]

如果s为奇数,则s,s + 2,...,s + 2(n - 1)都为奇数,可以表示为2i+1的形式。此时,我们注意到,异或结果的最后一位只取决于n的奇偶性,即n个1的异或值,如果n是奇数,那么最后一位就是1,反之如果n是偶数,则最后一位是0:

\[2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) + \underbrace{1\oplus...\oplus1}_{n} \]

那么实际上,我们可以把s为奇数和偶数得到的最终结果统一起来:

\[\begin{cases} 2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) + 1 & s和n均为奇数 \\ 2(\lfloor\frac{s}{2}\rfloor \oplus (\lfloor\frac{s}{2}\rfloor + 1) \oplus ... \oplus (\lfloor\frac{s}{2}\rfloor + n - 1)) & s和n不均为奇数 \end{cases} \]

我们令f(k)为从0异或到k的结果,则上面的式子可以化简为:

\[\begin{cases} 2(f(\lfloor\frac{s}{2}\rfloor + n - 1) \oplus f(\lfloor\frac{s}{2}\rfloor - 1)) + 1 & s和n均为奇数 \\ 2(f(\lfloor\frac{s}{2}\rfloor + n - 1) \oplus f(\lfloor\frac{s}{2}\rfloor - 1)) & s和n不均为奇数 \end{cases} \]

现在,我们只需计算出f(k)即可。计算f(k)这时就用到前面提到的公式了,可以假设k = 4i, 4i + 1,4i + 2,4i + 3分别算出结果:

\[\begin{cases} k & k = 4i \\ 1 & k = 4i + 1 \\ k + 1 & k = 4i + 2 \\ 0 & k = 4i + 3 \end{cases} \]

通过的代码如下:

class Solution {
public:
    int xorOperation(int n, int start) {
        int t = start >> 1;
        int res = helper(t - 1) ^ helper(t + n - 1);
        return (res << 1) | ((start & 0x1) & (n & 0x1));
    }

    int helper(int t)
    {
        int res = 0;
        switch(t & 0x3)
        {
            case 0:
            res = t;
            break;

            case 1:
            res = 1;
            break;

            case 2:
            res = t + 1;
            break;

            case 3:
            res = 0;
        }

        return res;
    }
};
posted @ 2022-01-12 00:16  异次元的归来  阅读(205)  评论(0编辑  收藏  举报