Subarray whose sum is closest to K

Given an array of positive and negative integers and an integer K. The task is to find the subarray which has its sum closest to k. In case of multiple answers, print any one.
Note: Closest here means abs(sum-k) should be minimal.

Examples:

Input: a[] = { -5, 12, -3, 4, -15, 6, 1 }, K = 2
Output: 1
The subarray {-3, 4} or {1} has sum = 1 which is the closest to K.

Input: a[] = { 2, 2, -1, 5, -3, -2 }, K = 7
Output: 6
Here the output can be 6 or 8
The subarray {2, 2, -1, 5} gives sum as 8 which has abs(8-7) = 1 which is same as that of the subarray {2, -1, 5} which has abs(6-7) = 1.

A naive approach is to check for all possible subarray sum using prefix sum. The complexity in that case will be O(N2).

An efficient solution will be to use C++ STL set and binary search to solve the following problem. Follow the below algorithm to solve the above problem.

Below is the implementation of the above approach.

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find the
// sum of subarray whose sum is
// closest to K
#include <bits/stdc++.h>
using namespace std;
  
// Function to find the sum of subarray
// whose sum is closest to K
int closestSubarraySumToK(int a[], int n, int k)
{
  
    // Declare a set
    set<int> s;
  
    // initially consider the
    // first subarray as the first
    // element in the array
    int presum = a[0];
  
    // insert
    s.insert(a[0]);
  
    // Initially let this difference
    // be the minimum
    int mini = abs(a[0] - k);
  
    // let this be the sum
    // of the subarray
    // to be searched initially
    int sum = presum;
  
    // iterate for all the array elements
    for (int i = 1; i < n; i++) {
  
        // calculate the prefix sum
        presum += a[i];
  
        // find the closest subarray
        // sum to by using lower_bound
        auto it = s.lower_bound(presum - k);
  
        // if it is the first element
        // in the set
        if (it == s.begin()) {
  
            // get the prefix sum till start
            // of the subarray
            int diff = *it;
  
            // if the subarray sum is closest to K
            // than the previous one
            if (abs((presum - diff) - k) < mini) {
  
                // update the minimal difference
                mini = abs((presum - diff) - k);
  
                // update the sum
                sum = presum - diff;
            }
        }
  
        // if the difference is
        // present in between
        else if (it != s.end()) {
  
            // get the prefix sum till start
            // of the subarray
            int diff = *it;
  
            // if the subarray sum is closest to K
            // than the previous one
            if (abs((presum - diff) - k) < mini) {
  
                // update the minimal difference
                mini = abs((presum - diff) - k);
  
                // update the sum
                sum = presum - diff;
            }
  
            // also check for the one before that
            // since the sum can be greater than
            // or less than K also
            it--;
  
            // get the prefix sum till start
            // of the subarray
            diff = *it;
  
            // if the subarray sum is closest to K
            // than the previous one
            if (abs((presum - diff) - k) < mini) {
  
                // update the minimal difference
                mini = abs((presum - diff) - k);
  
                // update the sum
                sum = presum - diff;
            }
        }
  
        // if there exists no such prefix sum
        // then the current prefix sum is
        // checked and updated
        else {
  
            // if the subarray sum is closest to K
            // than the previous one
            if (abs(presum - k) < mini) {
  
                // update the minimal difference
                mini = abs(presum - k);
  
                // update the sum
                sum = presum;
            }
        }
  
        // insert the current prefix sum
        s.insert(presum);
    }
  
    return sum;
}
  
// Driver Code
int main()
{
    int a[] = { -5, 12, -3, 4, -15, 6, 1 };
    int n = sizeof(a) / sizeof(a[0]);
    int k = 2;
  
    cout << closestSubarraySumToK(a, n, k);
    return 0;
}
chevron_right

Time Complexity: O(N log N)




Striver(underscore)79 at Codechef and codeforces D

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




Article Tags :