未排序数组中累加和小于或等于给定值的最长子数组长度

Posted zhaoyinghe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了未排序数组中累加和小于或等于给定值的最长子数组长度相关的知识,希望对你有一定的参考价值。

题目描述

给定一个无序数组arr,其中元素可正、可负、可0。给定一个整数k,求arr所有的子数组中累加和小于或等于k的最长子数组长度

要求

时间复杂度为O(n),空间复杂度为O(n)

示例

输入描述

第一行两个整数N, k。N表示数组长度,k的定义已在题目描述中给出
第二行N个整数表示数组内的数

输出描述

输出一个整数表示答案

示例1

输入

5 -2
3 -2 -4 0 6

输出

4

备注

(1 leq N leq 10^5)
$-10^9 leq k leq 10^9 $
$-100 leq arr_i leq100 $

思路比较巧妙,创建一个两个数组min_sum和ind,min_sum[i]表示到从输入数组末尾到i位置为止的最小子数组和,ind[i]记录这个数组的起始位置索引,注意这里是从后往前。
在求解的过程中,从前往后,对于每个位置计算满足条件最大子数组

n, k = map(int, input().strip().split(' '))
nums = list(map(int, input().strip().split(' ')))

min_sum = [0]*n
ind = [0]*n
min_sum[-1] = nums[-1]
ind[-1] = n-1
for i in range(n-1)[::-1]:
    min_sum[i] = min(min_sum[i+1], 0)+nums[i]
    if min_sum[i+1] <= 0:
        ind[i] = ind[i+1]
    else:
        ind[i] = i

#start表示子数组的开始,end表示结束位置后一位,s表示索引从start到end-1的子数组和
start = end = s = 0
res = 0
for start in range(n):
    end = max(end, start)
   # 对于每个start,end不必重新退回到新的start位置。这是因为start是向右移的,要寻找可能存在满足条件的更大的子数组的话,end只能在原有的end基础上右移,因此end不必要重新回到新的start位置。
    while end < n and s+min_sum[end] <= k:
        s += min_sum[end]
        end = ind[end]+1
    res = max(res, end-start)             #记录最长的子数组
    if end > start:                       #这里表示nums[start:end] > k,此时需要将start右移。当start移动到end-1时,此时s=0 
        s -= nums[start]
print(res)

参考资料

https://www.nowcoder.com/questionTerminal/3473e545d6924077a4f7cbc850408ade?f=discussion

以上是关于未排序数组中累加和小于或等于给定值的最长子数组长度的主要内容,如果未能解决你的问题,请参考以下文章

未排序数组中累加和为给定值的最长子数组长度

算法总结之 未排序正数数组中累加和为给定值的最长子数组长度

[程序员代码面试指南]数组和矩阵问题-未排序正数数组中累加和为给定值的最长子数组长度

一天一道算法题---未排序数组中累加和为给定值的最长子数组

累加和小于或等于定值得最长子数组的长度

读书笔记之《程序员代码面试指南(数组和矩阵问题)》