📜  所有元素<= k的子集的斐波那契总和

📅  最后修改于: 2021-05-30 18:03:03             🧑  作者: Mango

给定一个n个元素的数组,任务是找到该数组的一个子集的斐波那契总和,其中子集的每个元素<= k。
精确地找到F(A i 1 )+ F(A i 2 )+ F(A i 3 )+…+ F(A i x )) ,其中(A i 1 ,A i 2 ,…,A i x ) <= K和1 <=(i 1 ,i 2 ,…,i x )<= n。 F(i)是第i斐波那契数

例子 :

Input : arr = {1, 2, 3, 4, 2, 7}
        Query 1 : K = 2
        Query 2 : K = 6
Output : 3
         8

解释 :
查询1中,子集{1、2、2}是这样的子集,其中子集中的所有元素均<= k,在这种情况下为<= 2。子集的斐波那契总和= F(1)+ F(2)+ F(2)= 1 +1 + 1 = 3

查询2中,子集{1、2、3、4、2}是这样的子集,其中子集中的所有元素均<= k,在这种情况下为<= 6。子集的斐波那契总和= F(1)+ F(2)+ F(3)+ F(4)+ F(2)= 1 +1 + 2 + 3 +1 = 8

使用两种不同的查询技术来解决此问题,即:
1)在线查询
2)离线查询

在这两种方法中,唯一的共同的步骤是n斐波纳契number.For的有效技术来产生使用该Fibonacci数的n的产生。

产生斐波那契数的这种方法是两种查询技术所共有的。现在,看看如何使用通过这两种技术中的每一种生成的斐波那契数。

方法1(在线查询):
用这种技术,在查询到达时对其进行处理。首先,按升序对数组进行排序。查询特定的k后,对该排序后的数组使用二进制搜索,以找到该数组的值为&<= k的最后一个索引。我们将此位置称为x。

现在,由于数组已排序,

For all i <= x, a[i] <= x
i.e
a[i] <= a[x] for all i ∈ [1, x]

因此,要关注的子集是排序后的数组A中的A 1 ,A 2 ,A 3 ,…. A x ,斐波那契和为: F(A 1 )+ F(A 2 )+ F(A 3 )+ …+ F(A x )

使用前缀求和数组可以有效地找到子集A 1 ,A 2 ,A 3 ,…. A x的总和。

如果prefixFibSum [i]存储斐波那契和,直到已排序数组A的i索引,则数组子集从1到x的斐波那契和为prefixFibSum [x]

因此,子集[1…x]的斐波那契总和= prefixFibSum [x] ,prefixFibSum [x]可以计算如下:
prefixFibSum [X] = prefixFibSum [X – 1] + A [X]斐波那契数,其中,A [x]表示在阵列的x索引的数组元素。

C++
// C++ program to find fibonacci sum of 
// subarray where all elements <= k
#include 
  
using namespace std;
  
// Helper function that multiplies 2 matrices
// F and M of size 2*2, and puts the multiplication
// result back to F[][]
void multiply(int F[2][2], int M[2][2])
{
    int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
    int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
    int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
    int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
  
    F[0][0] = x;
    F[0][1] = y;
    F[1][0] = z;
    F[1][1] = w;
}
  
/* Helper function that calculates F[][]
   raise to the power n and puts the 
   result in F[][]  */
void power(int F[2][2], int n)
{
    int i;
    int M[2][2] = { { 1, 1 }, { 1, 0 } };
  
    // n - 1 times multiply the 
    // matrix to {{1, 0}, {0, 1}}
    for (i = 2; i <= n; i++)
        multiply(F, M);
}
  
// Returns the nth fibonacci number
int fib(int n)
{
    int F[2][2] = { { 1, 1 }, { 1, 0 } };
    if (n == 0)
        return 0;
    power(F, n - 1);
  
    return F[0][0];
}
  
int findLessThanK(int arr[], int n, int k)
{
    // find first index which is > k 
    // using lower_bound
    return (lower_bound(arr, arr + n, k + 1) 
                        - arr);
}
  
// Function to build Prefix Fibonacci Sum
int* buildPrefixFibonacciSum(int arr[], int n)
{
    // Allocate memory to prefix 
    // fibonacci sum array
    int* prefixFibSum = new int[n];
  
    // Traverse the array from 0 to n - 1,
    // when at the ith index then we calculate 
    // the a[i]th fibonacci number and calculate
    // the fibonacci sum till the ith index as
    // the sum of fibonacci sum till index i - 1 
    // and the a[i]th fibonacci number
    for (int i = 0; i < n; i++) 
    {
        int currFibNumber = fib(arr[i]);
        if (i == 0) {
            prefixFibSum[i] = currFibNumber;
        }
        else {
            prefixFibSum[i] = prefixFibSum[i - 1] 
                              + currFibNumber;
        }
    }
    return prefixFibSum;
}
  
// Return the answer for each query
int processQuery(int arr[], int prefixFibSum[], 
                 int n, int k)
{
  
    // index stores the index till where
    // the array elements are less than k
    int lessThanIndex = findLessThanK(arr, n, k);
  
    if (lessThanIndex == 0)
        return 0;
    return prefixFibSum[lessThanIndex - 1];
}
  
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 2, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    // sort the array arr
    sort(arr, arr + n);
  
    // Build the prefix fibonacci sum array
    int* prefixFibSum = 
         buildPrefixFibonacciSum(arr, n);
  
    // query array stores q queries
    int query[] = { 2, 6 };
    int q = sizeof(query) / sizeof(query[0]);
  
    for (int i = 0; i < q; i++) {
        int k = query[i];
        int ans = 
            processQuery(arr, prefixFibSum, n, k);
          
        cout << "Query  " << i + 1 << " : "
             << ans << endl;
    }
    return 0;
}


Java
// Java program to find fibonacci sum of 
// subarray where all elements <= k
import java.util.*;
  
class GFG
{
  
    // Helper function that multiplies 2 matrices
    // F and M of size 2*2, and puts the multiplication
    // result back to F[][]
    static void multiply(int[][] F, int[][] M)
    {
        int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
        int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
        int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
        int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
  
        F[0][0] = x;
        F[0][1] = y;
        F[1][0] = z;
        F[1][1] = w;
    }
  
    /*
    * Helper function that calculates F[][] 
    raise to the power n and puts the
    * result in F[][]
    */
    static void power(int[][] F, int n)
    {
        int i;
        int[][] M = { { 1, 1 }, { 1, 0 } };
  
        // n - 1 times multiply the
        // matrix to {{1, 0}, {0, 1}}
        for (i = 2; i <= n; i++)
            multiply(F, M);
    }
  
    // Returns the nth fibonacci number
    static int fib(int n) 
    {
        int[][] F = { { 1, 1 }, { 1, 0 } };
        if (n == 0)
            return 0;
        power(F, n - 1);
  
        return F[0][0];
    }
  
    static int findLessThanK(int arr[], int n, int k)
    {
        // find first index which is > k
        // using lower_bound
        return (lower_bound(arr, 0, n, k + 1));
    }
  
    static int lower_bound(int[] a, int low, 
                       int high, int element) 
    {
        while (low < high)
        {
            int middle = low + (high - low) / 2;
            if (element > a[middle])
                low = middle + 1;
            else
                high = middle;
        }
        return low;
    }
  
    // Function to build Prefix Fibonacci Sum
    static int[] buildPrefixFibonacciSum(int arr[], int n) 
    {
        // Allocate memory to prefix
        // fibonacci sum array
        int[] prefixFibSum = new int[n];
  
        // Traverse the array from 0 to n - 1,
        // when at the ith index then we calculate
        // the a[i]th fibonacci number and calculate
        // the fibonacci sum till the ith index as
        // the sum of fibonacci sum till index i - 1
        // and the a[i]th fibonacci number
        for (int i = 0; i < n; i++) 
        {
            int currFibNumber = fib(arr[i]);
            if (i == 0)
            {
                prefixFibSum[i] = currFibNumber;
            } 
            else
            {
                prefixFibSum[i] = prefixFibSum[i - 1] + 
                                        currFibNumber;
            }
        }
        return prefixFibSum;
    }
  
    // Return the answer for each query
    static int processQuery(int arr[], int prefixFibSum[],
                                            int n, int k) 
    {
  
        // index stores the index till where
        // the array elements are less than k
        int lessThanIndex = findLessThanK(arr, n, k);
  
        if (lessThanIndex == 0)
            return 0;
        return prefixFibSum[lessThanIndex - 1];
    }
  
    // Driver Code
    public static void main(String[] args) 
    {
        int arr[] = { 1, 2, 3, 4, 2, 7 };
        int n = arr.length;
  
        // sort the array arr
        Arrays.sort(arr);
  
        // Build the prefix fibonacci sum array
        int[] prefixFibSum = buildPrefixFibonacciSum(arr, n);
  
        // query array stores q queries
        int query[] = { 2, 6 };
        int q = query.length;
  
        for (int i = 0; i < q; i++) 
        {
            int k = query[i];
            int ans = processQuery(arr, prefixFibSum, n, k);
  
            System.out.print("Query " + (i + 1) + " : " + ans + "\n");
        }
    }
}
  
// This code is contributed by Rajput-Ji


C#
// C# program to find fibonacci sum of 
// subarray where all elements <= k
using System;
  
class GFG
{
  
    // Helper function that multiplies 2 matrices
    // F and M of size 2*2, and puts the multiplication
    // result back to F[,]
    static void multiply(int[,] F, int[,] M)
    {
        int x = F[0, 0] * M[0, 0] + F[0, 1] * M[1, 0];
        int y = F[0, 0] * M[0, 1] + F[0, 1] * M[1, 1];
        int z = F[1, 0] * M[0, 0] + F[1, 1] * M[1, 0];
        int w = F[1, 0] * M[0, 1] + F[1, 1] * M[1, 1];
  
        F[0, 0] = x;
        F[0, 1] = y;
        F[1, 0] = z;
        F[1, 1] = w;
    }
  
    /*
    * Helper function that calculates F[,] 
    raise to the power n and puts the
    * result in F[,]
    */
    static void power(int[,] F, int n)
    {
        int i;
        int[,] M = { { 1, 1 }, { 1, 0 } };
  
        // n - 1 times multiply the
        // matrix to {{1, 0}, {0, 1}}
        for (i = 2; i <= n; i++)
            multiply(F, M);
    }
  
    // Returns the nth fibonacci number
    static int fib(int n) 
    {
        int[,] F = {{ 1, 1 }, { 1, 0 }};
        if (n == 0)
            return 0;
        power(F, n - 1);
  
        return F[0, 0];
    }
  
    static int findLessThanK(int []arr, int n, int k)
    {
        // find first index which is > k
        // using lower_bound
        return (lower_bound(arr, 0, n, k + 1));
    }
  
    static int lower_bound(int[] a, int low, 
                    int high, int element) 
    {
        while (low < high)
        {
            int middle = low + (high - low) / 2;
            if (element > a[middle])
                low = middle + 1;
            else
                high = middle;
        }
        return low;
    }
  
    // Function to build Prefix Fibonacci Sum
    static int[] buildPrefixFibonacciSum(int []arr, int n) 
    {
        // Allocate memory to prefix
        // fibonacci sum array
        int[] prefixFibSum = new int[n];
  
        // Traverse the array from 0 to n - 1,
        // when at the ith index then we calculate
        // the a[i]th fibonacci number and calculate
        // the fibonacci sum till the ith index as
        // the sum of fibonacci sum till index i - 1
        // and the a[i]th fibonacci number
        for (int i = 0; i < n; i++) 
        {
            int currFibNumber = fib(arr[i]);
            if (i == 0)
            {
                prefixFibSum[i] = currFibNumber;
            } 
            else
            {
                prefixFibSum[i] = prefixFibSum[i - 1] + 
                                        currFibNumber;
            }
        }
        return prefixFibSum;
    }
  
    // Return the answer for each query
    static int processQuery(int []arr, int []prefixFibSum,
                                            int n, int k) 
    {
  
        // index stores the index till where
        // the array elements are less than k
        int lessThanIndex = findLessThanK(arr, n, k);
  
        if (lessThanIndex == 0)
            return 0;
        return prefixFibSum[lessThanIndex - 1];
    }
  
    // Driver Code
    public static void Main(String[] args) 
    {
        int []arr = { 1, 2, 3, 4, 2, 7 };
        int n = arr.Length;
  
        // sort the array arr
        Array.Sort(arr);
  
        // Build the prefix fibonacci sum array
        int[] prefixFibSum = buildPrefixFibonacciSum(arr, n);
  
        // query array stores q queries
        int []query = {2, 6};
        int q = query.Length;
  
        for (int i = 0; i < q; i++) 
        {
            int k = query[i];
            int ans = processQuery(arr, prefixFibSum, n, k);
  
            Console.Write("Query " + (i + 1) + " : " + ans + "\n");
        }
    }
}
  
// This code is contributed by PrinciRaj1992


输出:
Query  1 : 3
Query  2 : 8

时间复杂度: O(nlogn + qlogn)

方法2(离线查询):
在脱机查询中,存储查询并以特定顺序计算每个查询的答案,并以原始指定顺序存储和输出查询结果。

将每个查询存储为一对整数,其中该对的第一个成员是该查询的查询参数K,该对的第二个成员是该查询最初发生的索引。
例如,如果查询如下:
查询1:K = 13;
查询2:K = 3;
查询3:K = 8;
然后,存储查询1为其中13是K的针对该查询的值和1是指定它是第1的查询,类似于查询2和查询3被表示为分别的索引。

一次,所有单个查询都表示为整数对,并基于K以递增的方式对查询对数组进行排序。
例如,上面的查询在排序后看起来像{,,}。

排序查询背后的想法:
对查询进行排序的主要思想是,对于某个查询q i ,当子集中的元素小于k时,则对于所有查询q j ,其中i i <= K j,则这些元素存在,因此如果元素数组和查询(按K排序)都被排序,然后在数组上维护两个指针,在查询数组上维护另一个指针。 i,指向数组的i索引,
j,指向查询数组的j索引

然后,考虑以下伪代码:

while (i <= query[j].K) {
     fibonacciSum  = fibonacciSum + a[i]th Fibonacci number
     i = i + 1
}

因此,虽然子集中的元素小于或等于当前查询对的第一个成员(即K),但继续前进到下一个元素,同时将所需的斐波那契数加到当前总和上。一旦当前元素大于当前查询的参数K,就将当前和的当前值存储在名为q的ans的辅助数组中(即查询数),位于当前查询对的第二个成员所指向的索引处(即发生当前查询的原始索引)。

ans[query[j].original index] = current value of fibonacciSum

最后,打印ans数组,该数组按最初出现的顺序存储所有查询的结果。

// C++ program to find fibonacci sum of 
// subarray where all elements <= k
#include 
  
using namespace std;
  
// structure where K is the query parameter
// and original index is the index where the 
// query was originally present at.
struct offlineQuery {
    int K, originalIndex;
};
  
// function tp compare queries
bool cmp(offlineQuery q1, offlineQuery q2)
{
    return q1.K < q2.K;
}
  
/* Helper function that multiplies 2 matrices
  F and M of size 2*2, and puts the multiplication 
  result back to F[][] */
void multiply(int F[2][2], int M[2][2])
{
    int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
    int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
    int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
    int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
  
    F[0][0] = x;
    F[0][1] = y;
    F[1][0] = z;
    F[1][1] = w;
}
  
/* Helper function that calculates F[][] raise
   to the power n and puts the result in F[][]  */
void power(int F[2][2], int n)
{
    int i;
    int M[2][2] = { { 1, 1 }, { 1, 0 } };
  
    // n - 1 times multiply the 
    // matrix to {{1, 0}, {0, 1}}
    for (i = 2; i <= n; i++)
        multiply(F, M);
}
  
// Returns the nth fibonacci number
int fib(int n)
{
    int F[2][2] = { { 1, 1 }, { 1, 0 } };
    if (n == 0)
        return 0;
    power(F, n - 1);
  
    return F[0][0];
}
  
// Return the answer for each query
int* processQuery(int arr[], int queries[], 
                  int n, int q)
{
    // build offline queries where each query
    // is of type offlineQuery which stores
    // both K and original Index of the query
    // in the queries array
    offlineQuery* offlineQueries = 
                  new offlineQuery[q];
  
    // Allocate memory to store ans of each query
    int* ans = new int[q];
  
    for (int i = 0; i < q; i++) {
        int original_index = i;
        int K = queries[i];
        offlineQueries[i].K = K;
        offlineQueries[i].originalIndex = 
                          original_index;
    }
  
    // sort offlineQueries[]
    sort(offlineQueries, offlineQueries + q, cmp);
  
    // i is pointing to the current position
    // array arr fibonacciSum store the 
    // fibonacciSum till ith index
    int i = 0, fibonacciSum = 0;
      
    for (int j = 0; j < q; j++) 
    {
        int currK = offlineQueries[j].K;
        int currQueryIndex = 
            offlineQueries[j].originalIndex;
  
        // keep insering elements to subset
        // while elements are less than 
        // current query's K value
        while (i < n && arr[i] <= currK) 
        {
            fibonacciSum += fib(arr[i]);
            i++;
        }
  
        // store the current value of
        // fibonacci sum in the array ans
        // which stores results for the
        // queries in the original order
        ans[currQueryIndex] = fibonacciSum;
    }
  
    return ans;
}
  
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 2, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    // sort the array arr
    sort(arr, arr + n);
  
    // query array stores q queries
    int queries[] = { 2, 10, 6 };
    int q = sizeof(queries) / sizeof(queries[0]);
  
    // res stores the result of each query
    int* res = processQuery(arr, queries, n, q);
  
    for (int i = 0; i < q; i++) {
        int ans = res[i];
        cout << "Query  " << i + 1 << " : "
             << ans << endl;
    }
    return 0;
}
输出:
Query  1 : 3
Query  2 : 21
Query  3 : 8

时间复杂度: O(nlogn + qlogq)

如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。