leetcode-462.最少移动次数使数组元素相等
数学问题
题目详情
给你一个长度为 n
的整数数组 nums
,返回使所有数组元素相等需要的最少移动数。
在一步操作中,你可以使数组中的一个元素加 1 或者减 1
示例1:
输入:nums = [1,2,3]
输出:2
解释:
只需要两步操作(每步操作指南使一个元素加 1 或减 1):
[1,2,3] => [2,2,3] => [2,2,2]
示例2:
输入:nums = [1,10,2,9]
输出:16
思路:
本题难思考的点是如何知道以哪个数为基准数来使其他数都来靠近他,从而操作最少,结论就是排序后的中位数
不妨简单证明一下:
假如有一个排序好的数组例如2 3 4 5 6 7 8 假如要寻找一个小于2或者大于8的基准数来操作,那么肯定不如选择数组范围内的数来做基准数,自己随便试验试验就可以知道了,2 3 4 5 6 7 8要选2~8
3 4 5 6 7就要选3~7
4 5 6就要选4~6
…
由此我们可以看出选中位数是最好的,所以本题即可转换为
寻找中位数的问题
我们可以先排序数组,然后直接获得中位数,代码如下:
我的代码:
class Solution
{
public:
int minMoves2(vector<int>& nums)
{
sort(nums.begin(), nums.end()); // 排序
// 中位数
int n = nums.size(), mid = nums[n / 2], res = 0;
for (int num : nums)
{
res += abs(num - mid); //注意取绝对值
}
return res;
}
};
在思路中我们通过基准数可以想到:快速排序!里面同样有基准数这一利用,所以我们同样可以使用快速排序寻找第n / 2大的数(假设数组长n),有关快速排序的方法可以看leetcode-215.数组中的第K个最大元素:
leetcode-215.数组中的第K个最大元素 题解
这里我就直接使用C++已经有的库函数了,代码如下:
class Solution
{
public:
int minMoves2(vector<int>& nums)
{
int n = nums.size(), mid = n / 2, res = 0;
// 第mid大的数字归位,nums[mid]即为中位数
nth_element(nums.begin(), nums.begin() + mid, nums.end());
for (int num : nums)
{
res += abs(num - nums[mid]);
}
return res;
}
};