XOR 小于 k 的子数组
给定一个包含 n 个数字和一个数字 k 的数组。您必须编写一个程序来查找 xor 小于 k 的子数组的数量。
例子:
Input: arr[] = {8, 9, 10, 11, 12}, k=3
Output: 4
Sub-arrays [1:3], [2:3], [2:5], [4:5] have xor
values 2, 1, 0, 1 respectively.
Input: arr[] = {12, 4, 6, 8, 21}, k=8
Output: 4
朴素方法:朴素算法是简单地计算每个子数组的异或值,并与给定的数字 k 进行比较以找到答案。
下面是这种方法的实现:
C++
// C++ program to count number of
// subarrays with XOR less than k
#include
using namespace std;
// function to count number of
// subarrays with XOR less than k
int xorLessK(int arr[], int n, int k)
{
int count = 0;
// check all subarrays
for (int i = 0; i < n; i++) {
int tempXor = 0;
for (int j = i; j < n; j++) {
tempXor ^= arr[j];
if (tempXor < k)
count++;
}
}
return count;
}
// Driver program to test above function
int main()
{
int n, k = 3;
int arr[] = { 8, 9, 10, 11, 12 };
n = sizeof(arr) / sizeof(arr[0]);
cout << xorLessK(arr, n, k);
return 0;
}
Java
// Java program to count number of
// subarrays with XOR less than k
import java.io.*;
class GFG {
// function to count number of
// subarrays with XOR less than k
static int xorLessK(int arr[], int n, int k)
{
int count = 0;
// check all subarrays
for (int i = 0; i < n; i++) {
int tempXor = 0;
for (int j = i; j < n; j++) {
tempXor ^= arr[j];
if (tempXor < k)
count++;
}
}
return count;
}
// Driver program to test above function
public static void main (String[] args) {
int k = 3;
int arr[] = new int[] { 8, 9, 10, 11, 12 };
int n = arr.length;
System.out.println(xorLessK(arr, n, k));
}
}
Python3
# Python 3 program to count number of
# subarrays with XOR less than k
# function to count number of
# subarrays with XOR less than k
def xorLessK(arr, n, k):
count = 0
# check all subarrays
for i in range(n):
tempXor = 0
for j in range(i, n):
tempXor ^= arr[j]
if (tempXor < k):
count += 1
return count
# Driver Code
if __name__ == '__main__':
k = 3
arr = [8, 9, 10, 11, 12]
n = len(arr)
print(xorLessK(arr, n, k))
# This code is contributed by
# Sahil_shelangia
C#
// C# program to count number of
// subarrays with XOR less than k
using System;
class GFG {
// function to count number of
// subarrays with XOR less than k
static int xorLessK(int []arr, int n, int k)
{
int count = 0;
// check all subarrays
for (int i = 0; i < n; i++) {
int tempXor = 0;
for (int j = i; j < n; j++) {
tempXor ^= arr[j];
if (tempXor < k)
count++;
}
}
return count;
}
// Driver Code
static public void Main ()
{
int k = 3;
int []arr = new int[] {8, 9, 10,
11, 12 };
int n = arr.Length;
Console.WriteLine(xorLessK(arr, n, k));
}
}
PHP
Javascript
CPP
// C++ program to efficiently count number of
// subarrays with XOR less than k
#include
using namespace std;
// trie node
struct node
{
struct node* left;
struct node* right;
struct node* parent;
int leaf = 1;
};
// head node of trie
struct node* head = new node;
// initializing a new node
void init(node* temp)
{
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
temp->leaf = 1;
}
// updating the leaf count of trie
// nodes after insertion
void update(node* root)
{
// updating from bottom to
// top (leaf to root)
if (root->right && root->left) // sum of left and right
root->leaf = root->right->leaf + root->left->leaf;
else if (root->left) // only the left
root->leaf = root->left->leaf;
else if (root->right) // only the right
root->leaf = root->right->leaf;
if (root->parent) // updating the parent
update(root->parent);
}
// function to insert a new
// binary number in trie
void insert(string num, int level, node* root)
{
// if added the last node updates the
// leaf count using update function
if (level == -1)
{
update(root);
return;
}
// conversion to integer
int x = num[level] - '0';
if (x == 1)
{
// adding a right child
if (!root->right)
{
struct node* temp = new node;
init(temp);
root->right = temp;
temp->parent = root;
}
// calling for the right child
insert(num, level - 1, root->right);
}
else
{
// adding a left child
if (!root->left)
{
struct node* temp = new node;
init(temp);
root->left = temp;
temp->parent = root;
}
// calling for the left child
insert(num, level - 1, root->left);
}
}
// Utility function to find the number of
// subarrays with xor less than k
void solveUtil(string num, string k, int level,
node* root, int& ans)
{
if (level == -1)
return;
if (num[level] == '1')
{
// numbers in the right subtree
// added to answer
if (k[level] == '1')
{
if (root->right)
ans += root->right->leaf;
if (root->left)
solveUtil(num, k, level - 1, root->left, ans);
}
else
{
if (root->right)
solveUtil(num, k, level - 1, root->right, ans);
}
}
else
{
if (k[level] == '0')
{
if (root->left)
solveUtil(num, k, level - 1, root->left, ans);
}
else // then the numbers in the left
{
// subtree added to answer
if (root->left)
ans += root->left->leaf;
if (root->right)
solveUtil(num, k, level - 1, root->right, ans);
}
}
}
// function to find the number of
// subarrays with xor less than k
int solve(int a[], int n, int K)
{
int maxEle = K;
// Calculate maximum element in array
for (int i = 0; i < n; i++)
maxEle = max(maxEle, a[i]);
// maximum height of the Trie when
// the numbers are added as binary strings
int height = (int)ceil(1.0 * log2(maxEle)) + 1;
// string to store binary
// value of K
string k = "";
int temp = K;
// converting go to binary string and
// storing in k
for (int j = 0; j < height; j++)
{
k = k + char(temp % 2 + '0');
temp /= 2;
}
string init = "";
for (int i = 0; i < height; i++)
init += '0';
// adding 0 to the trie(initial value)
insert(init, height - 1, head);
int ans = 0;
temp = 0;
for (int i = 0; i < n; i++)
{
string s = "";
temp = (temp ^ a[i]);
// converting the array element to binary string s
for (int j = 0; j < height; j++)
{
s = s + char(temp % 2 + '0');
temp = temp >> 1;
}
solveUtil(s, k, height - 1, head, ans);
insert(s, height - 1, head);
}
return ans;
}
// Driver program to test above function
int main()
{
init(head); // initializing the head of trie
int n = 5, k = 3;
int arr[] = { 8, 9, 10, 11, 12 };
cout << solve(arr, n, k) << endl;
return 0;
}
输出:
3
时间复杂度: .
高效方法:一种有效的方法是计算所有前缀异或值,即所有 i 的 a[1:i]。
可以验证子数组a[l:r]的异或可以写成(a[1:l-1] xor a[1:r]),其中a[i, j]是所有的异或具有索引的元素,i <= index <= j。
解释:
我们将一个数字作为二进制数存储在 trie 中。左孩子将显示下一位为 0,右孩子将显示下一位为 1。
例如,下面给定的图片显示了 trie 中的数字 1001 和 1010。
如果 xor[i, j] 表示子数组 a[i, j] 中所有元素的异或,那么在索引 i 处,我们拥有的是一个具有 xor[1:1]、xor[1:2] 的 trie .....xor[1:i-1] 已经插入。现在我们以某种方式计算其中有多少(trie 中的数字)使得它的 xor 与 xor[1:i] 小于 k。这将涵盖所有以索引 i 结尾并具有 xor 的子数组,即 xor[j, i] <=k;
现在问题仍然存在,如何计算 xor 小于 k 的数字。因此,例如取第 i 个索引元素的当前位为 p,编号为 k 的当前位为 q,trie 中的当前节点为节点。
以 p=1,k=1 的情况为例。那么如果我们去右孩子,当前的异或将为0(因为右孩子意味着1并且p = 1,1(xor)1 = 0)。当k = 1时,所有数字都属于右孩子该节点将给出小于 k 的异或值。因此,我们将计算适合该节点的数字。
如果我们去左孩子,当前的 xor 将是 1(因为左孩子意味着 0 并且 p=1,0(xor)1=1)。因此,如果我们去左孩子,我们仍然可以找到 xor 小于 k 的数字,因此我们继续前进到左孩子。
因此,要计算给定节点下方的数字,我们修改特里树,每个节点还将存储该子树中的叶子数,并且在每次插入后都会修改。
对于 p 和 k 的不同值的其他三种情况可以以相同的方式解决以计算 xor 小于 k 的数字的数量。
以下是上述想法的 C++ 实现:
CPP
// C++ program to efficiently count number of
// subarrays with XOR less than k
#include
using namespace std;
// trie node
struct node
{
struct node* left;
struct node* right;
struct node* parent;
int leaf = 1;
};
// head node of trie
struct node* head = new node;
// initializing a new node
void init(node* temp)
{
temp->left = NULL;
temp->right = NULL;
temp->parent = NULL;
temp->leaf = 1;
}
// updating the leaf count of trie
// nodes after insertion
void update(node* root)
{
// updating from bottom to
// top (leaf to root)
if (root->right && root->left) // sum of left and right
root->leaf = root->right->leaf + root->left->leaf;
else if (root->left) // only the left
root->leaf = root->left->leaf;
else if (root->right) // only the right
root->leaf = root->right->leaf;
if (root->parent) // updating the parent
update(root->parent);
}
// function to insert a new
// binary number in trie
void insert(string num, int level, node* root)
{
// if added the last node updates the
// leaf count using update function
if (level == -1)
{
update(root);
return;
}
// conversion to integer
int x = num[level] - '0';
if (x == 1)
{
// adding a right child
if (!root->right)
{
struct node* temp = new node;
init(temp);
root->right = temp;
temp->parent = root;
}
// calling for the right child
insert(num, level - 1, root->right);
}
else
{
// adding a left child
if (!root->left)
{
struct node* temp = new node;
init(temp);
root->left = temp;
temp->parent = root;
}
// calling for the left child
insert(num, level - 1, root->left);
}
}
// Utility function to find the number of
// subarrays with xor less than k
void solveUtil(string num, string k, int level,
node* root, int& ans)
{
if (level == -1)
return;
if (num[level] == '1')
{
// numbers in the right subtree
// added to answer
if (k[level] == '1')
{
if (root->right)
ans += root->right->leaf;
if (root->left)
solveUtil(num, k, level - 1, root->left, ans);
}
else
{
if (root->right)
solveUtil(num, k, level - 1, root->right, ans);
}
}
else
{
if (k[level] == '0')
{
if (root->left)
solveUtil(num, k, level - 1, root->left, ans);
}
else // then the numbers in the left
{
// subtree added to answer
if (root->left)
ans += root->left->leaf;
if (root->right)
solveUtil(num, k, level - 1, root->right, ans);
}
}
}
// function to find the number of
// subarrays with xor less than k
int solve(int a[], int n, int K)
{
int maxEle = K;
// Calculate maximum element in array
for (int i = 0; i < n; i++)
maxEle = max(maxEle, a[i]);
// maximum height of the Trie when
// the numbers are added as binary strings
int height = (int)ceil(1.0 * log2(maxEle)) + 1;
// string to store binary
// value of K
string k = "";
int temp = K;
// converting go to binary string and
// storing in k
for (int j = 0; j < height; j++)
{
k = k + char(temp % 2 + '0');
temp /= 2;
}
string init = "";
for (int i = 0; i < height; i++)
init += '0';
// adding 0 to the trie(initial value)
insert(init, height - 1, head);
int ans = 0;
temp = 0;
for (int i = 0; i < n; i++)
{
string s = "";
temp = (temp ^ a[i]);
// converting the array element to binary string s
for (int j = 0; j < height; j++)
{
s = s + char(temp % 2 + '0');
temp = temp >> 1;
}
solveUtil(s, k, height - 1, head, ans);
insert(s, height - 1, head);
}
return ans;
}
// Driver program to test above function
int main()
{
init(head); // initializing the head of trie
int n = 5, k = 3;
int arr[] = { 8, 9, 10, 11, 12 };
cout << solve(arr, n, k) << endl;
return 0;
}
输出:
4
时间复杂度: O(n*log(max)),其中 max 是数组中的最大元素。
相关文章:
- 对最小异或值
- 最大子数组异或