📅  最后修改于: 2023-12-03 15:39:36.220000             🧑  作者: Mango
给定一个整数数组和一个目标值 k,找到该数组中和最接近 k 的子数组。返回这个子数组的和。
示例:
输入: nums = [1,5,7,9], k = 12
输出: 12
解释: 子数组 [1,5,7] 的和为 13,是所有和最接近 12 的子数组中最接近的。(注意是连续子数组)
题目中要求找到和最接近 k 的子数组,所以遍历数组的同时,需要记录当前的子数组和 sum,即从数组的某个位置开始向右一直累加的和。
假定当前子数组从下标 i 到 j,子数组的和为 sum,则 sum 与 k 的差值 diff 的绝对值为 |sum - k|。由于要找到最接近的子数组和,因此需要找到 diff 最小的子数组。
为了达到这个目的,我们可以使用一个变量 min_diff 来记录已经找到的与 k 最接近的子数组的和 sum,然后遍历整个数组,对于每个子数组的和 sum,计算 sum 与 k 的差值 diff,如果 diff 小于 min_diff,则更新 min_diff 和最终的结果 res。
在遍历完整个数组后,res 就是与 k 最接近的子数组的和。
以下是 Python 代码实现,时间复杂度为 O(N^2):
class Solution:
def closestSubarraySum(self, nums: List[int], k: int) -> int:
n = len(nums)
res = float('inf')
min_diff = float('inf')
for i in range(n):
for j in range(i, n):
sub_sum = sum(nums[i:j+1])
diff = abs(sub_sum - k)
if diff < min_diff:
min_diff = diff
res = sub_sum
return res
上述算法的时间复杂度为 O(N^2),对于大规模数据的情况,可能会出现超时问题。因此,我们需要考虑优化算法的时间复杂度。
一种常见的优化思路是使用前缀和。对于一个固定的下标 j,可以先预处理出从 0 到 j 的元素的和 prefix_sum[j],然后对于任意的 i(0 <= i <= j),从下标 i 到 j 的元素的和就可以通过 prefix_sum[j] - prefix_sum[i-1] 来计算。
这样,就可以在 O(1) 的时间复杂度内计算出任意子数组的和。因此,我们可以将时间复杂度优化为 O(N^2)。
以下是使用前缀和优化后的 Python 代码实现,时间复杂度为O(N^2):
class Solution:
def closestSubarraySum(self, nums: List[int], k: int) -> int:
n = len(nums)
res = float('inf')
min_diff = float('inf')
prefix_sum = [0] * (n + 1)
for i in range(1, n+1):
prefix_sum[i] = prefix_sum[i-1] + nums[i-1]
for i in range(n):
for j in range(i, n):
sub_sum = prefix_sum[j+1] - prefix_sum[i]
diff = abs(sub_sum - k)
if diff < min_diff:
min_diff = diff
res = sub_sum
return res
前缀和的时间复杂度为 O(N),可以将算法的时间复杂度降低到 O(N^2)。但是,我们还可以考虑更优秀的解法。
对于一个固定的下标 j,假设我们已经找到了前 j 个元素中与 k 最接近的子数组的和 sum,则对于下标 j+1,我们可以通过两种方法来计算与 k 最接近的子数组的和:
由于方法二只需要遍历前 j 个元素,可以在 O(N) 的时间复杂度内计算出以 j+1 为结尾的子数组中与 k 最接近的子数组,因此算法的时间复杂度为 O(N^2)。
以下是优化后的 Python 代码实现,时间复杂度为O(N^2):
class Solution:
def closestSubarraySum(self, nums: List[int], k: int) -> int:
n = len(nums)
res = float('inf')
min_diff = float('inf')
prefix_sum = [0] * (n + 1)
for i in range(1, n+1):
prefix_sum[i] = prefix_sum[i-1] + nums[i-1]
for j in range(n):
sum = prefix_sum[j+1]
for i in range(j+1):
sub_sum = sum - prefix_sum[i]
diff = abs(sub_sum - k)
if diff < min_diff:
min_diff = diff
res = sub_sum
return res
本题主要考察数组的遍历和前缀和的应用,并且需要注意时间复杂度优化的问题。通过本题的练习,可以提高数组操作和算法设计的能力。