Skip to content

Commit a504a23

Browse files
author
杨世超
committed
Create 1310. 子数组异或查询.md
1 parent ade2d16 commit a504a23

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
## [1310. 子数组异或查询](https://leetcode-cn.com/problems/xor-queries-of-a-subarray/)
2+
3+
- 标签:位运算、数组、前缀和
4+
- 难度:中等
5+
6+
## 题目大意
7+
8+
**描述**:给定一个正整数数组 `arr`,再给定一个对应的查询数组 `queries`,其中 `queries[i] = [Li, Ri]`
9+
10+
**要求**:对于每个查询 `queries[i]`,要求计算从 `Li``Ri` 的异或值(即 `arr[Li] ^ arr[Li+1] ^ ... ^ arr[Ri]`)作为本次查询的结果。并返回一个包含给定查询 `queries` 所有结果的数组。
11+
12+
**说明**
13+
14+
- $1 \le arr.length \le 3 * 10^4$。
15+
- $1 \le arr[i] \le 10^9$。
16+
- $1 \le queries.length \le 3 * 10^4$。
17+
- $queries[i].length == 2$。
18+
- $0 \le queries[i][0] \le queries[i][1] < arr.length$。
19+
20+
**示例**
21+
22+
```Python
23+
输入 arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]
24+
输出 [2,7,14,8]
25+
解释
26+
27+
数组中元素的二进制表示形式是:
28+
1 = 0001
29+
3 = 0011
30+
4 = 0100
31+
8 = 1000
32+
33+
查询的 XOR 值为:
34+
[0,1] = 1 xor 3 = 2
35+
[1,2] = 3 xor 4 = 7
36+
[0,3] = 1 xor 3 xor 4 xor 8 = 14
37+
[3,3] = 8
38+
```
39+
40+
## 解题思路
41+
42+
### 思路 1:线段树
43+
44+
- 使用数组 `res` 作为答案数组,用于存放每个查询的结果值。
45+
- 根据 `nums` 数组构建一棵线段树。
46+
- 然后遍历查询数组 `queries`。对于每个查询 `queries[i]`,在线段树中查询对应区间的异或值,将其结果存入答案数组 `res` 中。
47+
- 返回答案数组 `res` 即可。
48+
49+
这样构建线段树的时间复杂度为 $O(log_2n)$,单次区间查询的时间复杂度为 $O(log_2n)$。总体时间复杂度为 $O(k * log_2n)$,其中 $k$ 是查询次数。
50+
51+
### 思路 1:线段树代码
52+
53+
```Python
54+
# 线段树的节点类
55+
class SegTreeNode:
56+
def __init__(self, val=0):
57+
self.left = -1 # 区间左边界
58+
self.right = -1 # 区间右边界
59+
self.val = val # 节点值(区间值)
60+
self.lazy_tag = None # 区间和问题的延迟更新标记
61+
62+
63+
# 线段树类
64+
class SegmentTree:
65+
# 初始化线段树接口
66+
def __init__(self, nums, function):
67+
self.size = len(nums)
68+
self.tree = [SegTreeNode() for _ in range(4 * self.size)] # 维护 SegTreeNode 数组
69+
self.nums = nums # 原始数据
70+
self.function = function # function 是一个函数,左右区间的聚合方法
71+
if self.size > 0:
72+
self.__build(0, 0, self.size - 1)
73+
74+
# 单点更新接口:将 nums[i] 更改为 val
75+
def update_point(self, i, val):
76+
self.nums[i] = val
77+
self.__update_point(i, val, 0)
78+
79+
# 区间更新接口:将区间为 [q_left, q_right] 上的所有元素值加上 val
80+
def update_interval(self, q_left, q_right, val):
81+
self.__update_interval(q_left, q_right, val, 0)
82+
83+
# 区间查询接口:查询区间为 [q_left, q_right] 的区间值
84+
def query_interval(self, q_left, q_right):
85+
return self.__query_interval(q_left, q_right, 0)
86+
87+
# 获取 nums 数组接口:返回 nums 数组
88+
def get_nums(self):
89+
for i in range(self.size):
90+
self.nums[i] = self.query_interval(i, i)
91+
return self.nums
92+
93+
94+
# 以下为内部实现方法
95+
96+
# 构建线段树实现方法:节点的存储下标为 index,节点的区间为 [left, right]
97+
def __build(self, index, left, right):
98+
self.tree[index].left = left
99+
self.tree[index].right = right
100+
if left == right: # 叶子节点,节点值为对应位置的元素值
101+
self.tree[index].val = self.nums[left]
102+
return
103+
104+
mid = left + (right - left) // 2 # 左右节点划分点
105+
left_index = index * 2 + 1 # 左子节点的存储下标
106+
right_index = index * 2 + 2 # 右子节点的存储下标
107+
self.__build(left_index, left, mid) # 递归创建左子树
108+
self.__build(right_index, mid + 1, right) # 递归创建右子树
109+
self.__pushup(index) # 向上更新节点的区间值
110+
111+
112+
# 区间查询实现方法:在线段树中搜索区间为 [q_left, q_right] 的区间值
113+
def __query_interval(self, q_left, q_right, index):
114+
left = self.tree[index].left
115+
right = self.tree[index].right
116+
117+
if left >= q_left and right <= q_right: # 节点所在区间被 [q_left, q_right] 所覆盖
118+
return self.tree[index].val # 直接返回节点值
119+
if right < q_left or left > q_right: # 节点所在区间与 [q_left, q_right] 无关
120+
return 0
121+
122+
mid = left + (right - left) // 2 # 左右节点划分点
123+
left_index = index * 2 + 1 # 左子节点的存储下标
124+
right_index = index * 2 + 2 # 右子节点的存储下标
125+
res_left = 0 # 左子树查询结果
126+
res_right = 0 # 右子树查询结果
127+
if q_left <= mid: # 在左子树中查询
128+
res_left = self.__query_interval(q_left, q_right, left_index)
129+
if q_right > mid: # 在右子树中查询
130+
res_right = self.__query_interval(q_left, q_right, right_index)
131+
132+
return self.function(res_left, res_right) # 返回左右子树元素值的聚合计算结果
133+
134+
# 向上更新实现方法:更新下标为 index 的节点区间值 等于 该节点左右子节点元素值的聚合计算结果
135+
def __pushup(self, index):
136+
left_index = index * 2 + 1 # 左子节点的存储下标
137+
right_index = index * 2 + 2 # 右子节点的存储下标
138+
self.tree[index].val = self.function(self.tree[left_index].val, self.tree[right_index].val)
139+
140+
141+
class Solution:
142+
def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
143+
self.STree = SegmentTree(arr, lambda x, y: (x ^ y))
144+
res = []
145+
for query in queries:
146+
ans = self.STree.query_interval(query[0], query[1])
147+
res.append(ans)
148+
return res
149+
```

0 commit comments

Comments
 (0)