错误解法(解法可能有错,一种思路):
public class Solution {
private boolean finish(int[] nums){
if(nums.length == 0)
return true;
int temp = nums[0];
for(int i = 1; i < nums.length; i++){
if(nums[i] != temp)
return false;
}
return true;
}
public int minMoves(int[] nums) {
int count = 0;
while(!finish(nums)){//判断是否移动完成
Arrays.sort(nums);
//移动方法,排序,每次将前n-1个元素自增(总结规律发现这是最优的移动方式),也算是一种贪心,每次之后规模变化,问题形式不变
for(int i = 0; i < nums.length - 1; i++)
nums[i]++;
count++;
}
return count;
}
}
正解:
public class Solution {
public int minMoves(int[] nums) {
//这就是一个数学问题
//设sum是一开始数组nums中所有元素的和,minNum是一开始数组nums的最小元素,n是数组nums的长度
//假设在移动m次之后,数组中的所有元素相等,都为x
//那么根据等式恒等,得出:sum + m*(n-1) = x*n
//m*(n-1)代表移动m次后增加的值,因为每次移动n-1个元素
//实际上,x = minNum + m
//为什么x = minNum + m?
/*Let me explain why x = minNum + m
our goal is :increment minNum to be equal to maxNum
No matter how many add operations are executed,the goal won't change.
Every time we do the add operation,the min number in the array must participate in.
After an add operation,the minNum is still the min number(因为还有n-2个比它大的元素也增加了)
So the minNum participate in every add operation
So x = minNum + m
*/
//将x = minNum + m代入sum + m*(n-1) = x*n
//所以求解出 m = sum - minNum*n,这样求出的m是最小的,因为是按策略求得,知道相等时就结束了,之后还继续也可以再次相等,当然移动次数大于m
/*Actually, this problem could be solved by dynamic programming:
sort(nums)
let s = move(nums, 0:k)
then move(nums, 0:k+1) = s + abs(nums[k+1] - nums[k])
return sum(s)
In the end, you will find that this could written as sum(nums) - N * min;*/
//开始将思路转化成代码
//最后要求解的就是m:m = sum - minNum*n
//先求出minNum
int minNum = nums[0];
for(int num : nums){
minNum = Math.min(minNum, num);//依次比较
}
//求出sum
int sum = 0;
for(int num : nums){
sum += num;
}
int m = sum - minNum*nums.length;
/*//m还可以这样求,之不管将上面的过程合到了一个循环中完成
int m = 0;
for(int num : nums){
m += num - minNum;
}*/
return m;
}
}