LeetCode 题解工作台

使子数组元素和相等

给你一个下标从 0 开始的整数数组 arr 和一个整数 k 。数组 arr 是一个循环数组。换句话说,数组中的最后一个元素的下一个元素是数组中的第一个元素,数组中第一个元素的前一个元素是数组中的最后一个元素。 你可以执行下述运算任意次: 选中 arr 中任意一个元素,并使其值加上 1 或减去 1 。…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

中等 · 贪心·invariant

bolt

答案摘要

题目要求每个长度为 的子数组的元素总和相等,那么有以下等式成立: $$

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 贪心·invariant 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个下标从 0 开始的整数数组 arr 和一个整数 k 。数组 arr 是一个循环数组。换句话说,数组中的最后一个元素的下一个元素是数组中的第一个元素,数组中第一个元素的前一个元素是数组中的最后一个元素。

你可以执行下述运算任意次:

  • 选中 arr 中任意一个元素,并使其值加上 1 或减去 1

执行运算使每个长度为 k子数组 的元素总和都相等,返回所需要的最少运算次数。

子数组 是数组的一个连续部分。

 

示例 1:

输入:arr = [1,4,1,3], k = 2
输出:1
解释:在下标为 1 的元素那里执行一次运算,使其等于 3 。
执行运算后,数组变为 [1,3,1,3] 。
- 0 处起始的子数组为 [1, 3] ,元素总和为 4 
- 1 处起始的子数组为 [3, 1] ,元素总和为 4 
- 2 处起始的子数组为 [1, 3] ,元素总和为 4 
- 3 处起始的子数组为 [3, 1] ,元素总和为 4 

示例 2:

输入:arr = [2,5,5,7], k = 3
输出:5
解释:在下标为 0 的元素那里执行三次运算,使其等于 5 。在下标为 3 的元素那里执行两次运算,使其等于 5 。
执行运算后,数组变为 [5,5,5,5] 。
- 0 处起始的子数组为 [5, 5, 5] ,元素总和为 15
- 1 处起始的子数组为 [5, 5, 5] ,元素总和为 15
- 2 处起始的子数组为 [5, 5, 5] ,元素总和为 15
- 3 处起始的子数组为 [5, 5, 5] ,元素总和为 15

 

提示:

  • 1 <= k <= arr.length <= 105
  • 1 <= arr[i] <= 109
lightbulb

解题思路

方法一:数学(裴蜀定理) + 中位数贪心

题目要求每个长度为 kk 的子数组的元素总和相等,那么有以下等式成立:

arri+arri+1++arri+k1=arri+1+arri+2++arri+karr_i + arr_{i + 1} + \cdots + arr_{i + k - 1} = arr_{i + 1} + arr_{i + 2} + \cdots + arr_{i + k}

化简得:

arri=arri+karr_i = arr_{i + k}

也即是说,数组 arrarr 有一个大小为 kk 的循环节,而由于数组 arrarr 是一个循环数组,那么数组 arrarr 也有一个长度为 nn 的循环节。换句话说,数组 arrarr 上间隔为 kk,以及间隔为 nn 的元素均相等。即有:

arri=arri+k×x+n×yarr_i = arr_{i + k \times x + n \times y}

根据裴蜀定理,有 a×x+b×y=gcd(a,b)a \times x + b \times y = gcd(a, b),因此,有:

arri=arri+k×x+n×y=arri+gcd(k,n)arr_i = arr_{i + k \times x + n \times y} = arr_{i + gcd(k, n)}

因此,数组 arrarr 上的元素可以分为 gcd(k,n)gcd(k, n) 组,每组的元素间隔为 gcd(k,n)gcd(k, n),且每一组中的所有元素均相等。对于每一组,我们可以将其元素按照大小排序,然后取中位数,即可将该组中的所有元素变为中位数。对于所有组,我们将其中位数之差的绝对值求和,即为答案。

时间复杂度 O(n×logn)O(n \times \log n),空间复杂度 O(n)O(n)。其中 nn 为数组 arrarr 的长度。

1
2
3
4
5
6
7
8
9
10
11
class Solution:
    def makeSubKSumEqual(self, arr: List[int], k: int) -> int:
        n = len(arr)
        g = gcd(n, k)
        ans = 0
        for i in range(g):
            t = sorted(arr[i:n:g])
            mid = t[len(t) >> 1]
            ans += sum(abs(x - mid) for x in t)
        return ans
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    The interviewer mentions gcd(n, k), which is the clue that circular jumps by k form repeated index cycles.

  • question_mark

    They ask why equal k-window sums imply equality between specific elements, pushing you toward subtracting adjacent windows.

  • question_mark

    They care about minimum operations after the groups are found, which usually means recognizing median, not average, for absolute-change cost.

warning

常见陷阱

外企场景
  • error

    Trying to equalize every length-k window directly with prefix sums misses the stronger invariant that linked positions must become equal.

  • error

    Using the mean for each cycle gives the wrong minimum because this problem charges absolute unit changes, so the median is optimal.

  • error

    Forgetting the circular structure or visiting indices twice can break cycle construction, especially when k and n are not coprime.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Ask for the final transformed array instead of only the minimum cost, which means assigning each cycle to one chosen median value.

  • arrow_right_alt

    Replace unit change cost with weighted change cost, which changes how you choose the best target inside each cycle.

  • arrow_right_alt

    Remove the circular condition and use a linear array, where the adjacent-window invariant no longer creates the same modulo cycles.

help

常见问题

外企场景

使子数组元素和相等题解:贪心·invariant | LeetCode #2607 中等