LeetCode﹝异或ி﹞解码异或区间查询第k大异或值
Posted 白鳯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode﹝异或ி﹞解码异或区间查询第k大异或值相关的知识,希望对你有一定的参考价值。
【LeetCode】﹝异或ி﹞解码异或、区间查询、第k大异或值
文章目录
解码异或后的数组★
【题目】未知 整数数组 arr
由 n
个非负整数组成。
经编码后变为长度为 n - 1
的另一个整数数组 encoded
,其中 encoded[i] = arr[i] XOR arr[i + 1]
。例如,arr = [1,0,2,1]
经编码后得到 encoded = [1,2,3]
。
给你编码后的数组 encoded
和原数组 arr
的第一个元素 first(arr[0])
。
请解码返回原数组 arr
。可以证明答案存在并且是唯一的。
提示:
2 <= n <= 104
encoded.length == n - 1
0 <= encoded[i] <= 105
0 <= first <= 105
【示例】
输入:encoded = [1,2,3], first = 1
输出:[1,0,2,1]
解释:若 arr = [1,0,2,1] ,那么 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]
-----------------------------------------------------------------------------------------
输入:encoded = [6,2,7,3], first = 4
输出:[4,2,0,7,4]
【解题思路】
a ^ b = c
(已知a和异或结果c,按顺序推)
class Solution
public int[] decode(int[] encoded, int first)
int n = encoded.length;
int[] decoded = new int[n + 1];
decoded[0] = first;
for (int i = 0; i < n; i++)
decoded[i + 1] = decoded[i] ^ encoded[i];
return decoded;
解码异或后的排列★★
【题目】给你一个整数数组 perm
,它是前 n
个正整数的排列,且 n
是个 奇数 。
它被加密成另一个长度为 n - 1
的整数数组 encoded
,满足 encoded[i] = perm[i] XOR perm[i + 1]
。比方说,如果perm = [1,3,2]
,那么 encoded = [2,1]
。
给你encoded
数组,请你返回原始数组perm
。题目保证答案存在且唯一。
提示:
3 <= n < 105
n
是奇数。encoded.length == n - 1
【示例】
输入:encoded = [3,1]
输出:[1,2,3]
解释:如果 perm = [1,2,3] ,那么 encoded = [1 XOR 2,2 XOR 3] = [3,1]
------------------------------------------------------------------
输入:encoded = [6,5,4,6]
输出:[2,4,1,5,3]
【解题思路】
注意两点:n为奇数,这些数是前n个数字的排列
详细推导如下:
a b c d e f g
[a^b, b^c, c^d, d^e, e^f, f^g]
---------------------------------------------------------------------------------------
(除了最后一个元素的异或值)
(a^b) ^ (c^d) ^ (e^f) = a ^ b ^ c ^ d ^ e ^ f = except_last_xor
(所有元素的异或值)
a ^ b ^ c ^ d ^ e ^ f ^ g = all_xor
(求得最后一个元素)
all_xor ^ except_last_xor = g
这下反推即可
代码如下
class Solution
public int[] decode(int[] encoded)
int n = encoded.length + 1;
int xorN = 0;
for (int i = 0; i <= n; i++)
xorN ^= i;
int partXor = 0;
for (int i = 0; i < encoded.length; i += 2)
partXor ^= encoded[i];
int last = xorN ^ partXor;
int[] decoded = new int[n];
decoded[n - 1] = last;
for (int i = n - 2; i >= 0; i--)
decoded[i] = decoded[i + 1] ^ encoded[i];
return decoded;
找出所有子集的异或总和再求和★
【题目】一个数组的 异或总和 定义为数组中所有元素按位 XOR
的结果;如果数组为 空 ,则异或总和为 0
。
-
例如,数组
[2,5,6]
的 异或总和 为2 XOR 5 XOR 6 = 1
。给你一个数组
nums
,请你求出nums
中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。
**注意:**在本题中,元素 相同 的不同子集应 多次 计数。
数组 a
是数组 b
的一个 子集 的前提条件是:从 b
删除几个(也可能不删除)元素能够得到 a
。
提示:
1 <= nums.length <= 12
1 <= nums[i] <= 20
【示例】
输入:nums = [1,3]
输出:6
解释:[1,3] 共有 4 个子集:
- 空子集的异或总和是 0 。
- [1] 的异或总和为 1 。
- [3] 的异或总和为 3 。
- [1,3] 的异或总和为 1 XOR 3 = 2 。
0 + 1 + 3 + 2 = 6
【解题思路】
方法一:递归枚举(同求子集法相同)
题目中要求元素相同的不同子集应多次计数
,所以可以视为求不相同元素的子集
(这里有个坑,不能用求子集的回溯法,更新当前异或值时会影响到后面的结果~)
class Solution
int sum;
public int subsetXORSum(int[] nums)
sum = 0;
dfs(nums, 0, 0);
return sum;
private void dfs(int[] nums, int index, int curxor)
if (index == nums.length)
sum += curxor;
return;
dfs(nums, index + 1, curxor ^ nums[index]);
dfs(nums, index + 1, curxor);
方法二:迭代法枚举(二进制计数法)
class Solution
public int subsetXORSum(int[] nums)
int n = nums.length;
int sum = 0;
for (int i = 0; i < (1 << n); i++)
int t = 0;
for (int j = 0; j < n; j++)
if ((i >> j & 1) == 1)
t ^= nums[j];
sum += t;
return sum;
偷个懒,官方题解的二项式展开下次再看
形成两个异或相等数组的三元组数目★★
【题目】给你一个整数数组 arr
。
现需要从数组中取三个下标 i、j
和 k
,其中 (0 <= i < j <= k < arr.length
) 。
a
和 b
定义如下:
a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
注意:^
表示 按位异或 操作。
请返回能够令a == b
成立的三元组 (i, j , k)
的数目。
【示例】
输入:arr = [2,3,1,6,7]
输出:4
解释:满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
-------------------------------------------------------------
输入:arr = [1,1,1,1,1]
输出:10
【解题思路】
找到异或值为0的位置,因为 a ^ a = 0
,所以这些区间的元素可任意组合,共有j - i
种组合。
class Solution
public int countTriplets(int[] arr)
int res = 0;
for (int i = 0; i < arr.length; i++)
int t = 0;
for (int j = i; j < arr.length; j++)
t ^= arr[j];
if (j > i && t == 0)
res += j - i;
return res;
子数组异或查询★★
【题目】有一个正整数数组 arr
,现给你一个对应的查询数组 queries
,其中 queries[i] = [Li, Ri]
。
对于每个查询 i
,请你计算从 Li
到 Ri
的 XOR
值(即 arr[Li] xor arr[Li+1] xor ... xor arr[Ri]
)作为本次查询的结果。
并返回一个包含给定查询 queries
所有结果的数组。
提示:
1 <= arr.length <= 3 * 10^4
1 <= arr[i] <= 10^9
1 <= queries.length <= 3 * 10^4
queries[i].length == 2
0 <= queries[i][0] <= queries[i][1] < arr.length
【示例】
输入:arr = [1,3,4,8], queries = [[0,1],[1,2],[0,3],[3,3]]
输出:[2,7,14,8]
解释:
数组中元素的二进制表示形式是:
1 = 0001
3 = 0011
4 = 0100
8 = 1000
查询的 XOR 值为:
[0,1] = 1 xor 3 = 2
[1,2] = 3 xor 4 = 7
[0,3] = 1 xor 3 xor 4 xor 8 = 14
[3,3] = 8
【解题思路】
前缀数组
子数组异或查询思路同数组区间和一样,区间异或和区间和都可用前缀数组。
class Solution
public int[] xorQueries(int[] arr, int[][] queries)
int n = arr.length;
int[] preXor = new int[n + 1];
for (int i = 0; i < n; i++)
preXor[i + 1] = preXor[i] ^ arr[i];
int m = queries.length;
int[] res = new int[m];
for (int i = 0; i < m; i++)
res[i] = preXor[queries[i][0]] ^ preXor[queries[i][1] + 1];
return res;
数组中两个数的最大异或值★★
方法:前缀树思想
详细见往期博客【LeetCode】﹝前缀树ி﹞最长单词、键值映射、最大异或值
找出第 K 大的异或坐标值★★
【题目】给你一个二维矩阵 matrix
和一个整数 k
,矩阵大小为 m x n
由非负整数组成。
矩阵中坐标 (a, b)
的 值 可由对所有满足 0 <= i <= a < m 且 0 <= j <= b < n
的元素 matrix[i][j]
(下标从 0
开始计数)执行异或运算得到。
请你找出 matrix
的所有坐标中第 k
大的值(k 的值从 1
开始计数)。
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 1000
0 <= matrix[i][j] <= 106
1 <= k <= m * n
【示例】
输入:matrix = [[5,2],[1,6]], k = 1
输出:7
解释:坐标 (0,1) 的值是 5 XOR 2 = 7 ,为最大的值。
-------------------------------------------------
输入:matrix = [[5,2],[1,6]], k = 2
输出:5
解释:坐标 (0,0) 的值是 5 = 5 ,为第 2 大的值。
【解题思路】
二维前缀异或数组+优先队列
使用二维前缀异或数组,在优先队列中加入所有异或值,出队列第k个就是。
class Solution
public int kthLargestValue(int[][] matrix, int k)
int m = matrix.length, n = matrix[0].length;
int[][] pre = new int[m + 1][n + 1];
PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) ->
return b - a;
);
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
pre[i + 1][j + 1] = pre[i + 1][j] ^ pre[i][j + 1] ^ pre[i][j] ^ matrix[i][j];
queue.offer(pre[i + 1][j + 1]);
int cur = 0, t = -1;
while (k-- > 0)
cur = queue.poll();
return cur;
使所有区间的异或结果为零★★★
<难呀!!!>
以上是关于LeetCode﹝异或ி﹞解码异或区间查询第k大异或值的主要内容,如果未能解决你的问题,请参考以下文章