📅  最后修改于: 2023-12-03 15:09:55.397000             🧑  作者: Mango
总和可被 k 整除的最长子数组指的是一个数组中,连续的一段子数组的元素之和是 k 的倍数,并且这段子数组的长度是所有满足条件的子数组中最长的。
例如,对于数组 [4, 5, 0, -2, -3, 1] 和 k = 5,其总和可被 k 整除的最长子数组为 [4, 5, 0, -2, -3],其长度为 5。
我们可以先计算出数组的前缀和,即从数组开头一直累加到当前位置的元素和。令数组前缀和为 prefix_sum,则有:
prefix_sum[i] = nums[0] + nums[1] + ... + nums[i-1]
那么,以子数组 nums[i:j] 的元素和能够被 k 整除,就等价于 prefix_sum[j] 和 prefix_sum[i] 对 k 取模的结果相同。即:
(prefix_sum[j] - prefix_sum[i]) % k == 0
这个等式可以转化为:
prefix_sum[j] % k == prefix_sum[i] % k
使用一个哈希表来存储前缀和对 k 取模的结果,键为前缀和对 k 取模的值,值为该前缀和第一次出现的位置。
我们从左到右遍历数组,对于当前位置 i,假设其对应的前缀和对 k 取模的值为 mod_i。如果哈希表中已经有 mod_i 这个键,说明之前某个位置 j 对应的前缀和 mod_j 和 i 对应的前缀和 mod_i 模 k 的结果相同,因此子数组 nums[j+1:i] 的元素和一定是 k 的倍数。
由于我们要求得最长的子数组,因此需要让满足条件的子数组的长度最长,因此我们只需用一个变量 max_length 记录下到目前为止最长的满足条件的子数组的长度即可。
下面是代码实现:
def maxSubArray(nums: List[int], k: int) -> int:
prefix_sum = [0]
for num in nums:
prefix_sum.append((prefix_sum[-1] + num) % k)
mod_to_index = {0: 0}
max_length = 0
for i in range(1, len(prefix_sum)):
mod_i = prefix_sum[i]
if mod_i in mod_to_index:
length = i - mod_to_index[mod_i]
max_length = max(max_length, length)
else:
mod_to_index[mod_i] = i
return max_length
时间复杂度为 O(n),空间复杂度为 O(n),其中 n 是数组的长度。