题:https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/description/
题目
Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a move is incrementing a selected element by 1 or decrementing a selected element by 1.
You may assume the array’s length is at most 10,000.
Example:
Input:
[1,2,3]
Output:
2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]
题目大意
每次可以对一个数组元素加一或者减一,求最小的改变次数。
思路
这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:
设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。
设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。
方法一
先排序,时间复杂度:O(NlogN)
class Solution {
public int minMoves2(int[] nums) {
Arrays.sort(nums);
int move = 0;
int l = 0 , h = nums.length-1;
while(l<h){
move += nums[h] - nums[l];
l++;
h--;
}
return move;
}
}
方法二
使用快速选择找到中位数,时间复杂度 O(N)
class Solution {
public int partition(int[] nums,int l,int h){
int pivot = nums[l];
while(l<h){
while(l<h && nums[h]>=pivot)
h--;
nums[l] = nums[h];
while(l<h && nums[l]<=pivot)
l++;
nums[h] = nums[l];
}
nums[l] = pivot;
return l;
}
public int findKthSmallest(int[] nums,int k ){
int l =0,h = nums.length -1;
while(l<h){
int j = partition(nums,l,h);
if(j == k)
break;
if(j<k){
l = j+1;
}
else{
h = j-1;
}
}
return nums[k];
}
public int minMoves2(int[] nums) {
int move = 0;
int m = findKthSmallest(nums,nums.length/2);
for(int num:nums){
move += Math.abs(num - m);
}
return move;
}
}