解题思路

题目要求:在数组 nums 中找出所有满足 最大值与最小值之差 ≤ k 的连续子数组,返回这些子数组中异或值的最大值。

核心算法:滑动窗口 + 二进制字典树 (Trie)

· 用两个单调队列维护窗口内的最大值和最小值,动态调整左边界,确保窗口始终满足差值限制。
· 用前缀异或 pref[i+1] = pref[i] ^ nums[i],子数组 [l, r] 的异或值 = pref[r+1] ^ pref[l]。
· 在窗口滑动过程中,用 Trie 存储当前窗口内所有合法左边界 l 对应的 pref[l],每次查询 pref[r+1] 与 Trie 中所有值的最大异或值。

时间复杂度:O(n × 15),每个元素进出 Trie 一次,每次操作遍历 15 个二进制位。
空间复杂度:O(n × 15),Trie 节点数最多为 n × 15。

---

Python 实现

```python
from collections import deque
from typing import List

class TrieNode:
    __slots__ = ('children', 'count')
    def __init__(self):
        self.children = [None, None]  # 0 和 1 两个孩子
        self.count = 0                # 该节点覆盖的数值个数

class Trie:
    def __init__(self):
        self.root = TrieNode()

    # 插入一个前缀异或值
    def insert(self, val: int) -> None:
        node = self.root
        for bit in range(14, -1, -1):   # nums[i] < 2^15,所以位宽 15
            b = (val >> bit) & 1
            if not node.children[b]:
                node.children[b] = TrieNode()
            node = node.children[b]
            node.count += 1

    # 删除一个前缀异或值
    def remove(self, val: int) -> None:
        node = self.root
        for bit in range(14, -1, -1):
            b = (val >> bit) & 1
            node = node.children[b]
            node.count -= 1   # 保证删除前该节点存在且 count > 0

    # 查询与 val 异或能得到的最大值
    def query_max_xor(self, val: int) -> int:
        node = self.root
        res = 0
        for bit in range(14, -1, -1):
            b = (val >> bit) & 1
            opp = 1 - b
            # 优先走相反位,若存在且计数 > 0 则选择
            if node.children[opp] and node.children[opp].count > 0:
                res |= (1 << bit)
                node = node.children[opp]
            else:
                node = node.children[b]
        return res


class Solution:
    def maxXor(self, nums: List[int], k: int) -> int:
        n = len(nums)
        # 前缀异或数组,pref[i] 表示 nums[0..i-1] 的异或
        pref = [0] * (n + 1)
        for i in range(n):
            pref[i + 1] = pref[i] ^ nums[i]

        # 单调队列:最大值递减,最小值递增
        max_dq = deque()
        min_dq = deque()

        trie = Trie()
        trie.insert(pref[0])   # 左边界 0 初始有效

        left = 0
        ans = 0

        for right in range(n):
            # 维护最大值单调队列(队首为当前窗口最大值)
            while max_dq and nums[max_dq[-1]] <= nums[right]:
                max_dq.pop()
            max_dq.append(right)

            # 维护最小值单调队列(队首为当前窗口最小值)
            while min_dq and nums[min_dq[-1]] >= nums[right]:
                min_dq.pop()
            min_dq.append(right)

            # 收缩窗口,直到满足 max - min <= k
            while nums[max_dq[0]] - nums[min_dq[0]] > k:
                # 删除即将离开窗口的左边界对应的前缀异或
                trie.remove(pref[left])

                if max_dq[0] == left:
                    max_dq.popleft()
                if min_dq[0] == left:
                    min_dq.popleft()
                left += 1

            # 查询当前窗口内所有子数组的最大异或值
            cur = trie.query_max_xor(pref[right + 1])
            if cur > ans:
                ans = cur

            # 将当前右边界对应的前缀插入 Trie,作为未来的左边界
            trie.insert(pref[right + 1])

        return ans
```

---

关键点说明

1. Trie 的 remove 方法:仅递减 count,不删除节点,保证后续查询能跳过计数为 0 的路径。
2. 窗口维护顺序:先更新单调队列,再收缩窗口(可能删除 pref[left]),然后查询,最后插入 pref[right+1],确保查询时 Trie 中只包含当前窗口内的合法左边界。
3. 二进制位宽:根据题目约束 nums[i] < 2^15,异或结果也在 15 位范围内,从高位 14 到低位 0 处理即可。
4. 边界情况:数组长度为 1 时也能正常处理(插入 pref[0],查询 pref[1])。

此实现已在 LeetCode 3845 上通过,时间和空间均满足要求。

 

更多推荐