力扣-1486. 数组异或操作
1. 题目
题目地址(1486. 数组异或操作 - 力扣(LeetCode))
https://leetcode.cn/problems/xor-operation-in-an-array/?envType=study-plan-v2&envId=primers-list
题目描述
给你两个整数,n
和 start
。
数组 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
提示:
1 <= n <= 1000
0 <= start <= 1000
n == nums.length
2. 题解
2.1 模拟
思路
没有什么好讲的
代码
- 语言支持:C++
C++ Code:
class Solution {
public:
int xorOperation(int n, int start) {
int res = start;
for(int i = 1; i < n; i++){
start += 2;
res ^= start;
}
return res;
}
};
复杂度分析
令 n 为数组长度。
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(1)\)
2.2 位运算
思路
异或运算有着如下性质:
对于第五条进行解释, 可以看到如下例子, 四者异或运算结果位0(有1的位都出现了两次), 而 *4i 也只是将位进行向左平移而已, 并不影响异或结果
000
001
010
011
序言
这题我们需要计算\(start\oplus(start+2i)\oplus(start+4i)\oplus\cdots\oplus(start+(2(n-1)))\)
观察公式可以知道,这些数的奇偶性质相同,因此它们的二进制表示中的最低位或者均为 1,或者均为 0(因为加 2 * i, 肯定是加在第二位以及之后的高位上, 不可能加载最低位)。
于是我们可以把参与运算的数的二进制位的最低位提取出来单独处理(方便后续消除这里2*i中的i, 转换为我们擅长的公式)。
1. 处理最低位e
当且仅当 start 为奇数,且 n 也为奇数时,结果的二进制位的最低位才为 1。
(start为奇数,最低位才有1, n为奇数保证1出现奇数次, 异或结果才为1)
所以e = start & n & 1 (e如果想为1, 必须start和n的最低位都是1)
2.处理其他位
我们可以将公式转换为\((s\oplus(s+1)\oplus(s+2)\oplus\cdots\oplus(s+n-1))\times2+e\)
其中\(s=\lfloor\frac{start}{2}\rfloor\)
\(e\) 表示运算结果的最低位。即我们单独处理最低位,而舍去最低位后的数列恰成为一串连续的整数。
(这里由于\(s=\lfloor\frac{start}{2}\rfloor\) 相当于是 >> 1, 将最低位丢失, 所以单独计算)
这样我们可以描述一个函数 sumXor\((x)\),表示 0\(\oplus1\oplus2\oplus\cdots\oplus x\)。
利用异或运算的性质 5, 我们可以将计算该函数的复杂度降低到\(O(1)\) ,
因为以 4\(i\)为开头的连续四个整数异或的结果为 0,
所以 sumXor\((x)\)可以被表示为:
\(\begin{aligned}
\text{sumXor}(x)
&=
\begin{cases}x,
&x=4k,k\in Z\\(x-1)\oplus x,
&x=4k+1,k\in Z\\(x-2)\oplus(x-1)\oplus x,
&x=4k+2,k\in Z\\(x-3)\oplus(x-2)\oplus(x-1)\oplus x,
&x=4k+3,k\in Z&
\end{cases}
\end{aligned}\)
我们可以进一步简化
- 第一个原样
- \((x-1)\oplus x\), 由于x=4k+1,末尾为1,而\((x-1)\oplus x = ...1\oplus ...0 = 0...1 = 1\)
- \((x-2)\oplus(x-1)\oplus x\) 中x=4k+2,所以\((x-2)\oplus(x-1) = 1\), \(1\oplus x = x + 1(x=4k+2,末位为0,所以异或末位加1)\)
- 这个参考上面的性质5即可
\( \text{sumXor}(x)= \begin{cases}x, &x=4k,k\in Z\\1, &x=4k+1,k\in Z\\x+1, &x=4k+2,k\in Z\\0, &x=4k+3,k\in Z \end{cases} \)
总结:
\((s\oplus(s+1)\oplus(s+2)\oplus\cdots\oplus(s+n-1))\times2+e\)其中\(s=\lfloor\frac{start}{2}\rfloor\)
这样最后的结果即可表示为:\((\text{sumXor}(s-1)\oplus\text{sumXor}(s+n-1))\times2+e\)
($\text{sumXor}(s-1)$ 用于去除前s个数,因为任何数在异或出现两次=0)
代码
class Solution {
public:
int sumXor(int n){
if(n % 4 == 0) return n;
else if(n % 4 == 1) return 1;
else if(n % 4 == 2) return n+1;
else return 0;
}
int xorOperation(int n, int start) {
int s = start >> 1, e = start & n & 1;
int res = sumXor(s-1) ^ sumXor(s + n - 1);
return res << 1 | e;
}
};
复杂度分析
令 n 为数组长度。
- 时间复杂度:\(O(n)\)
- 空间复杂度:\(O(1)\)