前缀和题目:子数组异或查询
文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:子数组异或查询
出处:1310. 子数组异或查询
难度
4 级
题目描述
要求
给定一个正整数数组 arr \texttt{arr} arr,以及一个查询数组 queries \texttt{queries} queries,其中 queries[i] = [left i , right i ] \texttt{queries[i] = [left}_\texttt{i}\texttt{, right}_\texttt{i}\texttt{]} queries[i] = [lefti, righti]。
对于每个查询 i \texttt{i} i,计算从 left i \texttt{left}_\texttt{i} lefti 到 right i \texttt{right}_\texttt{i} righti 的异或值(即 arr[left i ] ⊕ arr[left i + 1] ⊕ … ⊕ arr[right i ] \texttt{arr[left}_\texttt{i}\texttt{]} \oplus \texttt{arr[left}_\texttt{i}\texttt{ + 1]} \oplus \ldots \oplus \texttt{arr[right}_\texttt{i}\texttt{]} arr[lefti]⊕arr[lefti + 1]⊕…⊕arr[righti])作为查询的结果。
返回一个数组 answer \texttt{answer} answer,其中 answer[i] \texttt{answer[i]} answer[i] 是第 i \texttt{i} i 个查询的结果。
示例
示例 1:
输入: arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]] \texttt{arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]} arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]
输出: [2,7,14,8] \texttt{[2,7,14,8]} [2,7,14,8]
解释:
数组中元素的二进制表示形式是:
1 = 0001 \texttt{1} = \texttt{0001} 1=0001
3 = 0011 \texttt{3} = \texttt{0011} 3=0011
4 = 0100 \texttt{4} = \texttt{0100} 4=0100
8 = 1000 \texttt{8} = \texttt{1000} 8=1000
查询的异或值为:
[0,1] = 1 ⊕ 3 = 2 \texttt{[0,1]} = \texttt{1} \oplus \texttt{3} = \texttt{2} [0,1]=1⊕3=2
[1,2] = 3 ⊕ 4 = 7 \texttt{[1,2]} = \texttt{3} \oplus \texttt{4} = \texttt{7} [1,2]=3⊕4=7
[0,3] = 1 ⊕ 3 ⊕ 4 ⊕ 8 = 14 \texttt{[0,3]} = \texttt{1} \oplus \texttt{3} \oplus \texttt{4} \oplus \texttt{8} = \texttt{14} [0,3]=1⊕3⊕4⊕8=14
[3,3] = 8 \texttt{[3,3]} = \texttt{8} [3,3]=8
示例 2:
输入: arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]] \texttt{arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]]} arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]]
输出: [8,0,4,4] \texttt{[8,0,4,4]} [8,0,4,4]
数据范围
- 1 ≤ arr.length ≤ 3 × 10 4 \texttt{1} \le \texttt{arr.length} \le \texttt{3} \times \texttt{10}^\texttt{4} 1≤arr.length≤3×104
- 1 ≤ arr[i] ≤ 10 9 \texttt{1} \le \texttt{arr[i]} \le \texttt{10}^\texttt{9} 1≤arr[i]≤109
- 1 ≤ queries.length ≤ 3 × 10 4 \texttt{1} \le \texttt{queries.length} \le \texttt{3} \times \texttt{10}^\texttt{4} 1≤queries.length≤3×104
- queries[i].length = 2 \texttt{queries[i].length} = \texttt{2} queries[i].length=2
- 0 ≤ left i ≤ right i < arr.length \texttt{0} \le \texttt{left}_\texttt{i} \le \texttt{right}_\texttt{i} < \texttt{arr.length} 0≤lefti≤righti<arr.length
解法
思路和算法
这道题要求对于每个查询计算子数组的元素按位异或。由于数组 arr \textit{arr} arr 的长度以及查询的个数最大为 3 × 10 4 3 \times 10^4 3×104,因此计算子数组的元素按位异或时,不能使用遍历子数组的做法,而是需要使用时间复杂度更低的做法。可以使用前缀和的思想实现。
首先计算数组 arr \textit{arr} arr 的前缀异或数组。创建前缀异或数组 prefixXors \textit{prefixXors} prefixXors,其长度为 arr \textit{arr} arr 的长度加 1 1 1, prefixXors [ i ] \textit{prefixXors}[i] prefixXors[i] 表示 arr \textit{arr} arr 的长度为 i i i 的前缀异或,即下标范围 [ 0 , i − 1 ] [0, i - 1] [0,i−1] 中的 i i i 个元素的按位异或。
根据按位异或的性质, prefixXors [ i + 1 ] ⊕ prefixXors [ i ] = arr [ i ] \textit{prefixXors}[i + 1] \oplus \textit{prefixXors}[i] = \textit{arr}[i] prefixXors[i+1]⊕prefixXors[i]=arr[i], prefixXors [ i + 1 ] = prefixXors [ i ] ⊕ arr [ i ] \textit{prefixXors}[i + 1] = \textit{prefixXors}[i] \oplus \textit{arr}[i] prefixXors[i+1]=prefixXors[i]⊕arr[i],由此可以遍历数组 arr \textit{arr} arr 一次计算得到前缀异或数组。
得到前缀异或数组 prefixXors \textit{prefixXors} prefixXors 之后,对于 queries [ i ] = [ left i , right i ] \textit{queries}[i] = [\textit{left}_i, \textit{right}_i] queries[i]=[lefti,righti],查询结果可以通过前缀异或数组得到:
answer [ i ] = prefixXors [ right i + 1 ] ⊕ prefixXors [ left i ] \textit{answer}[i] = \textit{prefixXors}[\textit{right}_i + 1] \oplus \textit{prefixXors}[\textit{left}_i] answer[i]=prefixXors[righti+1]⊕prefixXors[lefti]
代码
class Solution {public int[] xorQueries(int[] arr, int[][] queries) {int length = arr.length;int[] prefixXors = new int[length + 1];for (int i = 0; i < length; i++) {prefixXors[i + 1] = prefixXors[i] ^ arr[i];}int queriesCount = queries.length;int[] answer = new int[queriesCount];for (int i = 0; i < queriesCount; i++) {int left = queries[i][0], right = queries[i][1];answer[i] = prefixXors[right + 1] ^ prefixXors[left];}return answer;}
}
复杂度分析
-
时间复杂度: O ( n + q ) O(n + q) O(n+q),其中 n n n 是数组 arr \textit{arr} arr 的长度, q q q 是数组 queries \textit{queries} queries 的长度。需要遍历数组 arr \textit{arr} arr 一次计算前缀异或数组,需要遍历数组 queries \textit{queries} queries 一次计算每个查询的结果,每个查询的计算时间是 O ( 1 ) O(1) O(1),因此时间复杂度是 O ( n + q ) O(n + q) O(n+q)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 arr \textit{arr} arr 的长度。需要创建长度为 n + 1 n + 1 n+1 的前缀异或数组。