462. 最少移動次數使數組元素相等 II、
給你一個長度爲 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
來源:力扣(LeetCode)
鏈接:https://leetcode.cn/problems/minimum-moves-to-equal-array-elements-ii
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處
題目解析:
每次移動,可以將數組中的某一個數字加 1 或者減 1。求最少移動多少次,能讓數組中的數字都相等
分析
假設經過移動以後,所有的數字最終都等於 targettarget。
那麼這個 targettarget 的取值有兩種情況:在數組取值範圍外、在數組取值範圍內。
我們分情況討論。
情況一:targettarget 在數組取值範圍外
targettarget 在數組外的含義是 target > 數組最大值target>數組最大值或者 target < 數組最小值target<數組最小值。
假如 targettarget 在數組取值範圍之外,那麼把所有數字移動到 targettarget 一定比移動到邊界的移動次數更多!
以 nums = [1, 2, 3]nums=[1,2,3],target = 4target=4 爲例,說明爲什麼 targettarget 不能在數組之外,見圖:
因此,target一定在 nums 的最小值和最大值之間。
情況二:targettarget 在數組取值範圍內
當 targettarget在數組取值範圍內,那麼無論 targettarget 選擇何值,對於數組的最小值和最大值而言,它們移動到 targettarget 的次數之和一定是固定的!都等於 最大值 - 最小值最大值−最小值。
下圖以 nums = [1, 2, 3, 4, 5, 6]nums=[1,2,3,4,5,6],target = 4target=4 爲例,說明當 targettarget 取值在 [1,6][1,6] 範圍內,數字 11 與 數字 66 與 targettarget 的距離之和是定值 5;
然後,我們考慮去除 numsnums 的最大值、最小值以後的「子數組」,我們發現 targettarget 也需要選擇「子數組」範圍之內的數字。
因爲「情況一」中已經證明了,選擇「子數組」取值範圍外的數字不是最優。
如下圖所示, nums = [1, 2, 3, 4, 5, 6]nums=[1,2,3,4,5,6] ,當 targettarget 取 11 或者 66 時,對於子數組 [2,3,4,5][2,3,4,5] 不是最優:
綜上, targettarget 必須是不斷選擇 數組(以及子數組)最大值、最小值之間的數字,最終就是「中位數」。
根據上面的分析,可以得出結論:
- 當數組的長度是偶數時,targettarget 可以選擇 22 箇中位數任何一個,總移動次數相等。
- 當數組的長度是奇數時,中位數只有 11 個,因此 targettarget 選擇此中位數。
畫圖說明:
對於數組 nums = [1, 2, 3, 4, 5, 6]nums=[1,2,3,4,5,6] 而言,targettarget 一定選擇 33 或者 44。取兩者任何一個,結果是相等的。
當數組長度爲奇數時,target 一定選擇中位數。
當數組長度爲奇數時,target 一定選擇中位數。
代碼實現:
class Solution {
public:
int minMoves2(vector<int>& nums) {
sort(nums.begin(), nums.end());
const int N = nums.size();
int mid = nums[N / 2];
int res = 0;
for (int n : nums) {
res += abs(n - mid);
}
return res;
}
};