📅  最后修改于: 2023-12-03 15:08:03.265000             🧑  作者: Mango
在一个旋转有序数组中查找给定长度的最大和连续子数组是一个经典的问题,它要求我们在一个数组中找到一个指定长度的子数组,使得该子数组的元素和最大。
给定一个旋转有序数组 nums
和一个整数 k
,请你计算数组中长度为 k
的最大连续子数组的和并返回该值。
输入:nums = [3,4,5,6,7,1,2], k = 3
输出:18
解释:子数组 [6,7,1] 的全部元素可以加起来得到 18 。
输入:nums = [2,1,3], k = 3
输出:6
解释:子数组 [2,1,3] 的全部元素可以加起来得到 6 。
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^4
1 <= k <= nums.length
首先考虑最朴素的方法,即枚举数组 nums
中所有长度为 k
的子数组,计算它们的和并取最大值。时间复杂度为 $O(nk)$,其中 $n$ 是数组 nums
的长度。
def max_sum_of_k(nums, k):
n = len(nums)
res = float("-inf")
for i in range(n - k + 1):
s = sum(nums[i:i+k])
res = max(res, s)
return res
可以发现,对于每个固定长度的子数组,它与其相邻的子数组之间有 $k - 1$ 个元素是相同的,因此可以通过滑动窗口的方法避免重复计算。具体来说,定义两个指针 left
和 right
分别表示滑动窗口的左右边界,初始时 left = right = 0
。每次将窗口右边界向右移动一步,同时将窗口左边界向右移动一步以保持窗口长度不变,直到右边界到达数组末尾为止,过程中记录窗口内所有子数组的和的最大值即可。时间复杂度为 $O(n)$,其中 $n$ 是数组 nums
的长度。
def max_sum_of_k(nums, k):
n = len(nums)
res = float("-inf")
s = sum(nums[:k])
for i in range(k, n):
s += nums[i] - nums[i-k]
res = max(res, s)
return res
方法二依然存在一些冗余计算,例如当当前遍历的右端点 i
不在旋转点前面时,窗口中的每个元素都需要被累加一次。因此我们考虑去掉这样的冗余操作,具体来说:
rot
,可以采用二分查找的方法实现,时间复杂度为 $O(log\ n)$;rot
后,将数组分为两段,分别进行滑动窗口计算,时间复杂度为 $O(k + log\ n)$。def find_rot(nums):
n = len(nums)
left, right = 0, n-1
while left < right:
mid = left + (right - left) // 2
if nums[mid] < nums[right]:
right = mid
else:
left = mid + 1
return left
def max_sum_of_k(nums, k):
n = len(nums)
rot = find_rot(nums)
res = float("-inf")
# 计算窗口左半边的和
s = sum(nums[rot-k:rot])
for i in range(k, rot):
s += nums[i] - nums[i-k]
res = max(res, s)
# 计算窗口右半边的和
s = sum(nums[rot:rot+k])
for i in range(rot+k, n):
s += nums[i] - nums[i-k]
res = max(res, s)
return res