📜  XOR 小于 k 的子数组

📅  最后修改于: 2022-05-13 01:57:48.571000             🧑  作者: Mango

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

时间复杂度O(n^2) .
高效方法:一种有效的方法是计算所有前缀异或值,即所有 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。

特里1

如果 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 是数组中的最大元素。
相关文章

  • 对最小异或值
  • 最大子数组异或