返回 A 的最短的非空連續子數組的長度,該子數組的和至少爲 K數組
若是沒有和至少爲 K 的非空子數組,返回 -1 。隊列
示例 1:test
輸入:A = [1], K = 1
輸出:1queue
示例 2:方法
輸入:A = [1,2], K = 4
輸出:-1時間
示例 3:while
輸入:A = [2,-1,2], K = 3
輸出:3工作
1 <= A.length <= 50000
-10 ^ 5 <= A[i] <= 10 ^ 5
1 <= K <= 10 ^ 9return
這道題的關鍵在於咱們要知道各個區間的和。從而來判斷哪一個區間的和是知足要求的。用暴利解法逐個判斷是可行的,可是耗費的時間太多。由於暴力解法其實作了不少重複的工做。那麼爲了節省重複的計算,有個方法就是保存數組的前綴和數組。也就是用一個數組sum來記錄各個區間的和。也就是
sum[i]=arr[0]+arr[1]+……+arr[i-1]。這裏爲了計算方便,增長了覺得sum[0]=0。有了這個數組,就能夠很方便的求解任意區間的和。
好比要求區間[4,6]的和,就能夠用sum[6]-sum[4]。
那麼接下來的工做就是要將sum數組中的各個求和值入隊列。
(1) 當區間[0,i]的值比[0,i-1]的值要大的時候,就直接進隊列。
(2) 當區間[0…i]的值比區間[0….i-1]還要小的時候,那麼對於後面的位置,其實能夠忽略掉i-1,由於sum[n]-sum[i] > sum[n]-sum[n-1]。也就是[i,n]區間的值比[i-1,n]的值要大,並且更短。所以i-1這個位置就能夠被踢出隊列。
好比隊列裏面的數值以下:0,1,3,5,4。因爲4比5小,此時應該將5剔除出隊列,爲何呢,若是保留5在隊列裏面,當後面一個數組好比7進隊列的時候,隊列數組變成0,1,3,5,4,7。 這個時候計算區間和7-5明顯比7-4要小。並且[5,7]的區間長度爲2,[4,7]的區間長度爲1。所以5沒有必要存在於隊列中。隊裏中的值變爲0,1,3,4,7
每次完成隊列插入的操做後,就要開始對隊列裏面的區間進行計算了。
當隊列爲0,1的時候,1-0<4 不知足條件
當隊列爲0,1,3的時候,3-1<4 不知足條件
當隊列爲0,1,3,5的時候,5-0>4 知足條件,最小長度爲3。0出隊列,隊列變爲1,3,5 繼續比較5-1>4,最小長度爲2,1出隊列,隊列變爲3,5。
當隊列爲3,4的時候(因爲5比4小,所以出隊列), 4-3<4不知足條件
當隊列爲3,4,7的時候,7-3>=4,知足條件,最小長度爲2
代碼以下:
沒有采用隊列或者棧的結構,就用數組來存儲dquue,用dq_begin, dq_end, dq_size來分別表示數組的第一個,最後一個元素以及數組長度。
int shortestSubarray(int a[], int k, int len)
{
int *dqueue;
int *sum;
int i,dq_begin,dq_end,dq_size,min_length,lengh;
dqueue = (int *)malloc((len + 1) * sizeof(int));
sum = (int *)malloc(len * sizeof(int));
memset(sum, 0,len * sizeof(int));
memset(dqueue, 0, (len + 1) * sizeof(int));
dq_begin = 0;
dq_end = -1;
dq_size = 0;
min_length = len+1;
for (i = 1; i <= len; i++)
{
*(sum + i) = *(sum+i-1)+a[i-1];
}
for (i = 0; i <= len; i++)
{
if (i != 0)
{
while (dq_size > 0 && sum[dq_end] >= sum[i])
{
dq_end -= 1;
dq_size -= 1;
}
while (dq_size > 0 && sum[i] - sum[dq_begin] >= k)
{
lengh = i - dq_begin;
min_length = min_length >= lengh ? lengh : min_length;
dq_begin += 1;
dq_size -= 1;
}
}
dq_end += 1;
dqueue[dq_end] = i;
dq_size += 1;
}
return min_length;
}