📌  相关文章
📜  总和大于k的最大子数组

📅  最后修改于: 2021-04-29 09:42:11             🧑  作者: Mango

给定一个整数数组和一个值k,找到总和大于k的最大子数组的长度。

例子:

Input : arr[] = {-2, 1, 6, -3}, k = 5
Output : 2
Largest subarray with sum greater than
5 is  {1, 6}.

Input : arr[] = {2, -3, 3, 2, 0, -1}, k = 3
Output : 5
Largest subarray with sum greater than
3 is {2, -3, 3, 2, 0}.

推荐:请首先在IDE上尝试您的方法,然后查看解决方案。

一个简单的解决方案是逐个考虑每个子数组并找到其总和。如果总和大于k,则将该子数组的长度与到目前为止找到的最大长度进行比较。该解决方案的时间复杂度为O(n 2 )。

一个有效的解决方案是使用前缀和和二进制搜索。这个想法是遍历数组并将前缀和和相应的数组索引存储在成对的向量中。找到前缀总和后,按前缀总和的升序对向量进行排序,对于前缀总和相同的值,请根据索引进行排序。创建另一个数组minInd [],其中minInd [i]在排序的前缀和向量中存储范围为[0..i]的最小索引值。此后,开始遍历数组arr []并存储子数组arr [0..i]的总和。如果总和大于k,则总和大于k的最大子数组是长度为i + 1的arr [0..i]。如果总和小于或等于k,则其值大于或等于k到k + 1 –必须将总和加到至少k + 1。令该值为x。要将x加到总和上,可以从中减去-x,因为sum-(-x)= sum + x。因此,需要找到一个前缀数组arr [0..j](j

下面是上述方法的实现:

C++
// CPP program to find largest subarray
// having sum greater than k.
#include 
using namespace std;
  
// Comparison function used to sort preSum vector.
bool compare(const pair& a, 
             const pair& b)
{
    if (a.first == b.first)
        return a.second < b.second;
  
    return a.first < b.first;
}
  
// Function to find index in preSum vector upto which
// all prefix sum values are less than or equal to val.
int findInd(vector >& preSum, int n,
                                            int val)
{
  
    // Starting and ending index of search space.
    int l = 0;
    int h = n - 1;
    int mid;
  
    // To store required index value.
    int ans = -1;
  
    // If middle value is less than or equal to
    // val then index can lie in mid+1..n
    // else it lies in 0..mid-1.
    while (l <= h) {
        mid = (l + h) / 2;
        if (preSum[mid].first <= val) {
            ans = mid;
            l = mid + 1;
        }
        else
            h = mid - 1;
    }
  
    return ans;
}
  
// Function to find largest subarray having sum
// greater than or equal to k.
int largestSub(int arr[], int n, int k)
{
    int i;
  
    // Length of largest subarray.
    int maxlen = 0;
  
    // Vector to store pair of prefix sum
    // and corresponding ending index value.
    vector > preSum;
  
    // To store current value of prefix sum.
    int sum = 0;
  
    // To store minimum index value in range
    // 0..i of preSum vector.
    int minInd[n];
  
    // Insert values in preSum vector.
    for (i = 0; i < n; i++) {
        sum = sum + arr[i];
        preSum.push_back({ sum, i });
    }
  
    sort(preSum.begin(), preSum.end(), compare);
  
    // Update minInd array.
    minInd[0] = preSum[0].second;
  
    for (i = 1; i < n; i++) {
        minInd[i] = min(minInd[i - 1], preSum[i].second);
    }
  
    sum = 0;
    for (i = 0; i < n; i++) {
        sum = sum + arr[i];
  
        // If sum is greater than k, then answer
        // is i+1.
        if (sum > k)
            maxlen = i + 1;
  
        // If the sum is less than or equal to k, then
        // find if there is a prefix array having sum
        // that needs to be added to the current sum to
        // make its value greater than k. If yes, then
        // compare the length of updated subarray with
        // maximum length found so far.
        else {
            int ind = findInd(preSum, n, sum - k - 1);
            if (ind != -1 && minInd[ind] < i)
                maxlen = max(maxlen, i - minInd[ind]);
        }
    }
  
    return maxlen;
}
  
// Driver code.
int main()
{
    int arr[] = { -2, 1, 6, -3 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    int k = 5;
  
    cout << largestSub(arr, n, k);
    return 0;
}


Python3
# Python3 program to find largest subarray 
# having sum greater than k. 
  
# Comparison function used to 
# sort preSum vector. 
def compare(a, b): 
  
    if a[0] == b[0]: 
        return a[1] < b[1] 
  
    return a[0] < b[0] 
  
# Function to find index in preSum vector 
# upto which all prefix sum values are less 
# than or equal to val. 
def findInd(preSum, n, val): 
  
    # Starting and ending index of 
    # search space. 
    l, h = 0, n - 1
  
    # To store required index value. 
    ans = -1
  
    # If middle value is less than or equal  
    # to val then index can lie in mid+1..n 
    # else it lies in 0..mid-1. 
    while l <= h: 
        mid = (l + h) // 2
        if preSum[mid][0] <= val: 
            ans = mid 
            l = mid + 1
          
        else:
            h = mid - 1
  
    return ans 
  
# Function to find largest subarray having
# sum greater than or equal to k. 
def largestSub(arr, n, k): 
  
    # Length of largest subarray. 
    maxlen = 0
  
    # Vector to store pair of prefix sum 
    # and corresponding ending index value. 
    preSum = [] 
  
    # To store the current value of prefix sum. 
    Sum = 0
  
    # To store minimum index value in range 
    # 0..i of preSum vector. 
    minInd = [None] * (n) 
  
    # Insert values in preSum vector. 
    for i in range(0, n): 
        Sum = Sum + arr[i] 
        preSum.append([Sum, i]) 
      
    preSum.sort()
      
    # Update minInd array. 
    minInd[0] = preSum[0][1] 
  
    for i in range(1, n): 
        minInd[i] = min(minInd[i - 1], 
                        preSum[i][1]) 
      
    Sum = 0
    for i in range(0, n): 
        Sum = Sum + arr[i] 
  
        # If sum is greater than k, then 
        # answer is i+1. 
        if Sum > k:
            maxlen = i + 1
  
        # If sum is less than or equal to k, 
        # then find if there is a prefix array 
        # having sum that needs to be added to
        # current sum to make its value greater 
        # than k. If yes, then compare length 
        # of updated subarray with maximum 
        # length found so far. 
        else:
            ind = findInd(preSum, n, Sum - k - 1) 
            if ind != -1 and minInd[ind] < i: 
                maxlen = max(maxlen, i - minInd[ind]) 
  
    return maxlen 
  
# Driver code. 
if __name__ == "__main__":
  
    arr = [-2, 1, 6, -3] 
    n = len(arr) 
  
    k = 5
  
    print(largestSub(arr, n, k)) 
      
# This code is contributed 
# by Rituraj Jain


输出:
2

时间复杂度: O(nlogn)
辅助空间: O(n)