📌  相关文章
📜  按 K 个索引逆时针旋转 Array 的范围求和查询(1)

📅  最后修改于: 2023-12-03 15:25:53.384000             🧑  作者: Mango

按 K 个索引逆时针旋转 Array 的范围求和查询

简介

这个题目需要我们对一个长度为n的数组进行k次旋转操作,然后对于给定的左右下标范围[l, r],求出该范围内所有数字的和。这个问题可以通过前缀和来解决,但是旋转会给我们带来一定的麻烦。本文将介绍如何使用Python解决这个问题。

解法

第一步是对整个数组进行旋转,这个可以通过切片操作实现,具体来说就是将数组的后k个元素移到前面:nums = nums[-k:] + nums[:-k]。现在数组的前k个元素就是原先数组的后k个元素,我们将这个数组拆分成两部分:A 和 B,用len_B表示B的长度,那么B的范围就是[len_A, n)。我们将A和B各自进行前缀和操作,得到数组PA和PB。

PA和PB分别为A和B的前缀和数组,PA[i]表示数组A的前i个元素的和,PB[i]表示数组B的前i个元素的和。现在我们可以将[l, r]范围分为三个部分,如下图所示:

  |-----|       |-----------------|          |-----|
  A      B      A                 B         A     B
  |-------------- l -----------------|---- r ----|
              len_A     

第一部分在数组PA中,第二部分在数组PB中,第三部分在A和B中,下面将分别计算三个部分的和。

首先是第一部分,我们需要计算从0到l-1这个范围内所有元素的和,这个值为PA[l-1],如果l-1<0,则PA[l-1]为0。

然后是第二部分,与第一部分类似,我们需要计算从0到r-len_A-1这个范围内所有元素的和,这个值为PB[r-len_A-1],如果r-len_A-1<0,则PB[r-len_A-1]为0。

最后是第三部分,这个部分稍微麻烦一些,因为它在A和B两个数组中,我们需要将A和B拼接起来,然后再计算这个范围内的和。具体来说,我们可以计算整个数组的前缀和,然后减去PA[l-1]和PB[r-len_A-1]的值即可。因为PA[l-1]里面包含了B数组的一部分,而PB[r-len_A-1]里面包含了A数组的一部分,我们需要把这部分减去。

最后将三部分的和相加即可得到答案。

代码实现
def rotate_and_query(nums, k, l, r):
    n = len(nums)
    nums = nums[-k:] + nums[:-k]
    len_A = n - k
    PA = [0] * len_A
    PB = [0] * k
    for i in range(len_A):
        PA[i] = nums[i] + (PA[i-1] if i > 0 else 0)
    for i in range(k):
        PB[i] = nums[i+len_A] + (PB[i-1] if i > 0 else 0)
    ans = 0
    ans += PA[l-1] if l > 0 else 0
    ans += PB[r-len_A-1] if r-len_A-1 >= 0 else 0
    ans += sum(nums[l:r+1]) - (PA[l-1] if l > 0 else 0) - (PB[r-len_A-1] if r-len_A-1 >= 0 else 0)
    return ans
总结

这个问题需要我们注意到旋转会带来的前缀和问题。具体来说,我们需要将原问题转化为三个部分的和:PA[l-1]、PB[r-len_A-1]和sum(nums[l:r+1])-(PA[l-1] if l > 0 else 0)-(PB[r-len_A-1] if r-len_A-1 >= 0 else 0)。其中PA[l-1]用于表示A数组中前l个元素的和,PB[r-len_A-1]用于表示B数组中前r-len_A个元素的和,sum(nums[l:r+1])用于表示A和B数组中的和。最后三个部分相加即可得到答案。

完整程序可见github