| 
 | 1 | +### 题目描述  | 
 | 2 | + | 
 | 3 | +这是 LeetCode 上的 **[462. 最少移动次数使数组元素相等 II](https://leetcode.cn/problems/minimum-moves-to-equal-array-elements-ii/solution/by-ac_oier-db44/)** ,难度为 **简单**。  | 
 | 4 | + | 
 | 5 | +Tag : 「数学」  | 
 | 6 | + | 
 | 7 | + | 
 | 8 | + | 
 | 9 | +给你一个长度为 $n$ 的整数数组 $nums,ドル返回使所有数组元素相等需要的最少移动数。  | 
 | 10 | + | 
 | 11 | +在一步操作中,你可以使数组中的一个元素加 1ドル$ 或者减 1ドル$ 。  | 
 | 12 | + | 
 | 13 | +示例 1:  | 
 | 14 | +```  | 
 | 15 | +输入:nums = [1,2,3]  | 
 | 16 | + | 
 | 17 | +输出:2  | 
 | 18 | + | 
 | 19 | +解释:  | 
 | 20 | +只需要两步操作(每步操作指南使一个元素加 1 或减 1):  | 
 | 21 | +[1,2,3] => [2,2,3] => [2,2,2]  | 
 | 22 | +```  | 
 | 23 | +示例 2:  | 
 | 24 | +```  | 
 | 25 | +输入:nums = [1,10,2,9]  | 
 | 26 | + | 
 | 27 | +输出:16  | 
 | 28 | +```  | 
 | 29 | + | 
 | 30 | +提示:  | 
 | 31 | +* $n == nums.length$  | 
 | 32 | +* 1ドル <= nums.length <= 10^5$  | 
 | 33 | +* $-10^9 <= nums[i] <= 10^9$  | 
 | 34 | + | 
 | 35 | +---  | 
 | 36 | + | 
 | 37 | +### 数学  | 
 | 38 | + | 
 | 39 | +假定所有的 $nums[i]$ 均位于数轴上的 $nums[i]$ 的位置,题目要求我们在数轴上找出一个点 $t,ドル使得所有 $nums[i]$ 到 $t$ 的距离之和最小。  | 
 | 40 | + | 
 | 41 | +**首先,容易证明 $t$ 不可能位于最小的 $nums[i]$ 的左侧,也不可能位于最大的 $nums[i]$ 的右侧,否则我们「至少」能够将目标点调整为 最小的 $nums[i]$ 或 最大的 $nums[i]$ 来得到更小的距离总和。**  | 
 | 42 | + | 
 | 43 | +> 其实由上述这一点进行推广,已经可以证明最优点必然是在中间点($nums$ 数量为奇数时)或者中间两点形成的闭区间中的任意点($nums$ 数量为偶数时)。  | 
 | 44 | +但为了证明更加直观,我们仍从「反证法」的角度进行证明。  | 
 | 45 | + | 
 | 46 | +我们根据每个 $nums[i]$ 位于 $t$ 的左侧还是右侧进行划分:假设位于 $t$ 左侧的 $nums[i]$ 对答案的贡献为 $A,ドル位于 $t$ 右侧的 $nums[i]$ 对答案的贡献为 $B,ドル最终目的是为了让 $A + B$ 最小。  | 
 | 47 | + | 
 | 48 | +我们猜想当 $t$ 取中位数时,$A + B$ 取得最小值,并通过「反证法」进行证明:  | 
 | 49 | + | 
 | 50 | +* 假设真实最优解 $t'$ 位于中位数 $t$ 的 左侧:假设调整距离为 $d,ドル导致变化的点数为 $x,ドル则有左边总和为 $A - xd,ドル右边总和为 $B + (n - x)d,ドル总和为 $A + B - 2xd + nd,ドル如果要使得结果更好,需要满足 $nd - 2xd < 0,ドル即满足 $x > \frac{n}{2},ドル这与我们本身 $t$ 为中位数,即左右两边数的个数均为 $\frac{n}{2}$ 冲突(特别地,当 $nums$ 为偶数时,且目标点位于中间两点中的任一点时,左右数的个数并非为 $\frac{n}{2},ドル但距离总和情况与 $t$ 位于两点间的其余点的情况一致);  | 
 | 51 | + | 
 | 52 | +* 假设真实最优解 $t'$ 位于中位数 $t$ 的 右侧:同理。  | 
 | 53 | + | 
 | 54 | +代码:  | 
 | 55 | +```Java  | 
 | 56 | +class Solution {  | 
 | 57 | + public int minMoves2(int[] nums) {  | 
 | 58 | + Arrays.sort(nums);  | 
 | 59 | + int n = nums.length, t = nums[(n - 1) / 2], ans = 0;  | 
 | 60 | + for (int i : nums) ans += Math.abs(t - i);  | 
 | 61 | + return ans;  | 
 | 62 | + }  | 
 | 63 | +}  | 
 | 64 | +```  | 
 | 65 | +* 时间复杂度:$O(n\log{n})$  | 
 | 66 | +* 空间复杂度:$O(\log{n})$  | 
 | 67 | + | 
 | 68 | +---  | 
 | 69 | + | 
 | 70 | +### 最后  | 
 | 71 | + | 
 | 72 | +这是我们「刷穿 LeetCode」系列文章的第 `No.462` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。  | 
 | 73 | + | 
 | 74 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。  | 
 | 75 | + | 
 | 76 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。  | 
 | 77 | + | 
 | 78 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。  | 
 | 79 | + | 
0 commit comments