Q:给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动将会使 n - 1 个元素增加 1。
示例:
输入:
[1,2,3]
输出:
3
解释:
只需要3次移动(注意每次移动会增加两个元素的值):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]
A:
- 暴力法的基础上,考虑到为了让最小元素等于最大元素,至少需要加 k 次。在那之后,最大元素可能发生变化。因此,我们一次性增加增量 k=max-min,并将移动次数增加 k。然后,对整个数组进行扫描,找到新的最大值和最小值,重复这一过程直到最大元素和最小元素相等。
要注意的是考虑可能最大值有多个。
但超时了。
public int minMoves(int[] nums) {
if (nums.length <= 1)
return 0;
int count = 0;
while (true) {
int minIndex = 0;
int maxIndex = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] < nums[minIndex])
minIndex = i;
if (nums[i] > nums[maxIndex])
maxIndex = i;
}
int max = nums[maxIndex];
int min = nums[minIndex];
if (min == max) {
break;
}
int temp = max - min;
count += temp;
for (int i = 0; i < nums.length; i++) {
if (i != maxIndex)
nums[i] += temp;
}
}
return count;
}
- 数学法
将除了一个元素之外的全部元素+1,等价于将该元素-1,因为我们只对元素的相对大小感兴趣。因此,该问题简化为需要进行的减法次数。显然,我们只需要将所有的数都减到最小的数即可。为了找到答案,我们不需要真的操作这些元素。只需要(moves = sum_{i=0}^{n-1}(a[i]-min))即可
public class Solution {
public int minMoves(int[] nums) {
int moves = 0, min = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
min = Math.min(min, nums[i]);
}
for (int i = 0; i < nums.length; i++) {
moves += nums[i] - min;
}
return moves;
}
}