Shortest Subarray with Sum at Least K

Jyothi
3 min readMar 12, 2022

--

Given an integer array nums and an integer k, return the length of the shortest non-empty subarray of nums with a sum of at least k. If there is no such subarray, return -1.

A subarray is a contiguous part of an array.

Really hard problem.

Below is C sol using monotonic Q:

/* monotonic dequeue/queue approach
In this approach queue always contains elements in increasing/decreasing order
In this dequeue method, elements can be removed either from top(pop) or from start (dequeue).
In a loop if the current sum - queue_begin_sum >=k , dequeue the element
update the result
if the top > current sum
pop element
*/
#define printf(...)
int shortestSubarray(int* ar, int ns, int k){
int ii=0, sind=0, top =0, res = ns+1, dqind;

long queue[ns][2], csum=0;
while (ii<ns){
if (ar[ii] >= k)
return 1;
csum += ar[ii];
printf("csum %d, ii %d, sind %d, k %d , res %d, top %d\n", csum, ii, sind, k, res, top);
if ((csum >=k) && (res > (ii+1))) res = ii+1;
dqind = -1;
/* check if there are elements in queue and
if csum-queue_start >= k , dequeue*/
while ((sind!=top) && ((csum - queue[sind][0]) >= k)){
printf("sind %d, top %d, csum %d, qval %d k %d\n",
sind, top, csum, queue[sind][0], k);
dqind = queue[sind][1]; sind++;
}

/* if there is dequeued element , update res */
if ((dqind > -1) && (res > (ii-dqind))) res = ii-dqind;

/* pop the elements bigger than csum */
while ((sind!=top) && (csum < queue[top-1][0])){
printf("sind %d, top %d, csum %d, topqval %d k %d\n",
sind, top, csum, queue[top-1][0], k);
top--;}

/* add to queue*/
queue[top][0] = csum; queue[top++][1] = ii;
/* printf("Qn %d:\n", top-sind);
for (int jj=sind; jj<top;jj++){
printf("Q%d: sum %d, ind %d\n", jj, queue[jj][0],queue[jj][1]);
} */
ii++;
}
return (res == ns+1)? -1: res;
}

My other failed approaches:

#ifdef SOL1
/* BR approach */
int shortestSubarray(int* ar, int ns, int k){
int ii, jj, res = INT_MAX;
int sum;
for (ii=0; ii<ns; ii++){
sum = 0;
for (jj=ii; jj<ns; jj++){
sum += ar[jj];
if ((sum >= k) && ((jj-ii+1)<res)){
res = jj-ii+1;
if (res == 1)
return res;
}
}
}
if (res == INT_MAX) return -1;
return res;
}
#endif
#ifdef SOL2
/* Below is two pointers or sliding window approach.
initialise the start index and end index to 0
in loop go through end of array:
keep incrementing current sum with the current element
if the current sum >= target
update the result value
now start compressing the current sum by reducing with start index elements till the current sum < k
note : this above logic works only if no -ve numbers */
int shortestSubarray(int* ar, int ns, int k){
int csum=0, sind=0, ii=0;
int res = ns+1;
while (ii<ns){
/* add current element to current sum */
csum += ar[ii];
/* check if current sum > k */
while (csum >= k) {
printf("csum %d, ii %d, sind %d, k %d , res %d, diff %d, ng_ind %d\n", csum, ii, sind, k, res, (ii-sind+1));
/* if number of csum elements < previously stored value */
if (res > (ii-sind+1))
res = ii - sind +1;

/* compress the current sum by reducing elements
from start index */
if (sind < ii)
csum -= ar[sind++];
else
break;
}
ii++;
}
return (res == ns+1)? -1: res;
}
#endif

Good explanation at https://www.youtube.com/watch?v=K0NgGYEAkA4

Can we solve this problem in any other way.

Please do comment.

--

--

Responses (1)