使用C++查找和为k^m形式的子数组个数,其中m>=0


在本文中,我们将解释如何使用C++解决求和为k^m形式(m>=0)的子数组个数的问题。给定一个数组arr[]和一个整数K,我们需要找到和为K^m形式的子数组个数,其中m大于等于零,也就是说,我们需要找到和等于K的某个非负幂的子数组个数。

Input: arr[] = { 2, 2, 2, 2 } K = 2

Output: 8

Sub-arrays with below indexes are valid:
[1, 1], [2, 2], [3, 3], [4, 4], [1, 2],
[2, 3], [3, 4], [1, 4]

Input: arr[] = { 3, -6, -3, 12 } K = -3

Output: 3

主要有两种方法:

暴力法

这种方法会遍历所有子数组,并检查它们的和是否为K的正整数幂;如果是,则计数器加一。

示例

#include <bits/stdc++.h>
#define MAX 1000000
using namespace std;
int main(){
   int arr[] = {2, 2, 2, 2}; // given array
   int k = 2; // given integer
   int n = sizeof(arr) / sizeof(arr[0]); // the size of our array
   int answer = 0; // counter variable
   for(int i = 0; i < n; i++){
      int sum = 0;
      for(int j = i; j < n; j++){ // this will loop will make all the subarrays
         sum += arr[j];
         int b = 1;
         while(b < MAX && sum > b) // k^m Max should be 10^6
            b *= k;
         if(b == sum) // if b == sum then increment count
            answer++;
      }
   }
   cout << answer << "\n";
}

输出

8

然而,这种方法效率不高,因为程序的时间复杂度为O(N*N*log(K)),其中N是数组的大小,K是用户给定的整数。

这种复杂度并不理想,因为在约束条件较高时,处理时间会过长。因此,我们将尝试另一种方法,以便在约束条件较高时也能使用该程序。

高效方法

这种方法将使用前缀和和映射来减少处理量,从而显著降低时间复杂度。

示例

#include <bits/stdc++.h>
#define ll long long
#define MAX 1000000
using namespace std;
int main(){
   int arr[] = {2, 2, 2, 2}; // The given array
   int n = sizeof(arr) / sizeof(arr[0]); // size of our array
   int k = 2; // given integer
   ll prefix_sum[MAX];
   prefix_sum[0] = 0;
   partial_sum(arr, arr + n, prefix_sum + 1); // making prefix sum array
   ll sum;
   if (k == 1){
   // we are going to check separately for 1
      sum = 0;
      map<ll, int> m;
   for (int i = n; i >= 0; i--){
      // If m[a+b] = c, then add c to the current sum.
      if (m.find(prefix_sum[i] + 1) != m.end())
         sum += m[prefix_sum[i] + 1];
         // Increase count of prefix sum.
         m[prefix_sum[i]]++;
      }
      cout << sum << "\n";
   }
   else if (k == -1){
      // we are going to check separately for -1
      sum = 0;
      map<ll, int> m;
      for (int i = n; i >= 0; i--){
         // If m[a+b] = c, then add c to the current sum.
         if (m.find(prefix_sum[i] + 1) != m.end())
            sum += m[prefix_sum[i] + 1];

         if (m.find(prefix_sum[i] - 1) != m.end())
            sum += m[prefix_sum[i] - 1];

         // Increase count of prefix sum.
         m[prefix_sum[i]]++;
      }
      cout << sum << "\n";
   }
   else{
      sum = 0;
      ll b;
      map<ll, int> m;
      for (int i = n; i >= 0; i--){
         b = 1;
         while (b < MAX){ // we are not going to check for more than 10^6
            // If m[a+b] = c, then add c to the current sum.
            if (m.find(prefix_sum[i] + b) != m.end())
               sum += m[prefix_sum[i] + b];
               b *= k;
         }
         m[prefix_sum[i]]++;
      }
      cout << sum << "\n";
   }
   return 0;
}

输出

8

结论

我们解决了查找和为k^m形式(m>=0)的子数组个数的问题,时间复杂度为O(nlog(k)log(n))。我们还学习了该问题的C++程序以及解决该问题的完整方法(常规方法和高效方法)。可以使用C、Java、Python和其他语言编写相同的程序。希望本文对您有所帮助。

更新于:2021年11月25日

94次浏览

开启你的职业生涯

完成课程获得认证

开始学习
广告
© . All rights reserved.