给你一个长度为 n
的整数数组 nums
,返回使所有数组元素相等需要的最小操作数。
在一次操作中,你可以使数组中的一个元素加 1
或者减 1
。
测试用例经过设计以使答案在 32 位 整数范围内。
示例 1:
输入:nums = [1,2,3] 输出:2 解释: 只需要两次操作(每次操作指南使一个元素加 1 或减 1): [1,2,3] => [2,2,3] => [2,2,2]
示例 2:
输入:nums = [1,10,2,9] 输出:16
提示:
n == nums.length
1 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
解法1:排序
假设数组元素都变成 x 时,所需的移动数最少,那么 x 需要满足什么性质呢?
为了简化讨论,我们先假定数组长度 n 是偶数。我们将数组 nums 从小到大进行排序,然后将数组进行首尾配对,从而划分为多个数对,并将这些数对组成区间:
当 x 同时位于以上区间内时,所需的移动数最少,总移动数为
证明:对于某一个区间 [nums[i] ,nums[n−1−i] ],该区间对应的数对所需要的移动数为
∣nums[n−1−i] −x∣+∣nums[i] −x∣≥∣nums[n−1−i] −x−(nums[i] −x)∣=nums[n−1−i] −nums[i] ,当且仅当 x∈[nums[i] ,nums[n−1−i] ] 时,等号成立。
在上述区间中,后一个区间是前一个区间的子集,因此只要 x∈[nums[n/2−1] ,nums[n/2] ],就满足要求。
当 n 为奇数时,我们将排序后的数组中间的元素 nums[n/2] 当成区间 [nums[n/2] ,nums[n/2] ] 看待,则 x∈[nums[n/2] , nums[n/2] ] 即 x=nums[n/2] 时,所需的移动数最少。
综上所述,所有元素都变成 nums[n/2] 时,所需的移动数最少。
Java版:
class Solution {
public int minMoves2(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int mid = (n - 1) / 2;
int ans = 0;
for (int i = 0; i < n; i++) {
if (i < mid) {
ans += nums[mid] - nums[i];
} else {
ans += nums[i] - nums[mid];
}
}
return ans;
}
}
或
class Solution {
public int minMoves2(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int mid = n / 2;
int ans = 0;
for (int i = 0; i < n; i++) {
if (i < mid) {
ans += nums[mid] - nums[i];
} else {
ans += nums[i] - nums[mid];
}
}
return ans;
}
}
Python3版:
class Solution:
def minMoves2(self, nums: List[int]) -> int:
nums.sort()
n = len(nums)
mid = (n - 1) // 2
ans = 0
for i in range(n):
if i < mid:
ans += nums[mid] - nums[i]
else:
ans += nums[i] - nums[mid]
return ans
或
class Solution:
def minMoves2(self, nums: List[int]) -> int:
nums.sort()
n = len(nums)
mid = n // 2
ans = 0
for i in range(n):
if i < mid:
ans += nums[mid] - nums[i]
else:
ans += nums[i] - nums[mid]
return ans
复杂度分析
- 时间复杂度:O(nlogn),其中 n 是数组 nums 的长度。排序需要 O(nlogn) 的时间。
- 空间复杂度:O(logn)。排序需要 O(logn) 的递归栈空间。