大家好,我是 @负雪明烛。
解题方法:转化
转化过程
在刷题的过程中,很多题目需要通过转化变成一个更巧妙的解法,转化后效率则大大提升。
本题目为:
数组长度为 $n$,每次让 $n - 1$ 个元素加 $1$,问让所有元素相等的最少操作次数。
注意最终目的是让所有元素相等。
参考一下物理中「相对运动」的概念,我们变化一下参考系:让 $n - 1$ 个元素加 $1$ ,与让最大的元素减 $1$ 的效果一样:差值变化相同。
所以,我们可以把题目转化为:
数组长度为 $n$,每次让 $1$ 个元素减 $1$,问让所有元素相等的最少操作次数。
很显然,做法是最小元素不变,把其余所有的元素都降低到最小元素。这样的操作次数是最少的。
示例
以题目的示例 1 作为说明:
输入 :nums = [1, 2, 3] 输出:3 解释:把 2 和 3 都减小到 1,需要 3 次操作。 [1, 2, 3] -> [1, 1, 3] -> [1, 1, 2] -> [1, 1, 1]
算法详细步骤
算法一:累加 diff
- 计算 $nums$ 的最小值 $minVal$;
- 累加把 $nums$ 中每个元素降低为最小值需要的操作步骤 $num - minVal$。
算法二:求和
在算法一的基础上,我们发现累加可以转化为:
sum(nums) - minVal * N
这是一个更简洁的算法。
代码
代码一:不使用库函数
基于算法一,Python / C++ / Java 代码如下:
class Solution(object):
def minMoves(self, nums):
minVal = float("inf")
for num in nums:
minVal = min(minVal, num)
res = 0
for num in nums:
res += num - minVal
return res
class Solution {
public:
int minMoves(vector<int>& nums) {
int minVal = INT_MAX;
for (int num : nums) {
if (num < minVal)
minVal = num;
}
int res = 0;
for (int num : nums) {
res += num - minVal;
}
return res;
}
};
class Solution {
public int minMoves(int[] nums) {
int minVal = Integer.MAX_VALUE;
for (int num : nums) {
if (num < minVal)
minVal = num;
}
int res = 0;
for (int num : nums) {
res += num - minVal;
}
return res;
}
}
代码二:使用库函数
基于算法二,使用库函数。
Python / C++ / Java 代码如下:
class Solution(object):
def minMoves(self, nums):
minVal = min(nums)
return sum(num - minVal for num in nums)
class Solution {
public:
int minMoves(vector<int>& nums) {
int minVal = *min_element(nums.begin(), nums.end());
int res = 0;
for (int num : nums) {
res += num - minVal;
}
return res;
}
};
class Solution {
public int minMoves(int[] nums) {
int minVal = Arrays.stream(nums).min().getAsInt();
int res = 0;
for (int num : nums) {
res += num - minVal;
}
return res;
}
}
代码三:基于算法二
通过库函数求和 与 最小值。
Python / C++ / Java 代码如下:
class Solution(object):
def minMoves(self, nums):
return sum(nums) - min(nums) * len(nums)
class Solution {
public:
int minMoves(vector<int>& nums) {
int minVal = *min_element(nums.begin(), nums.end());
int sum = accumulate(nums.begin(), nums.end(), 0);
return sum - minVal * nums.size();
}
};
class Solution {
public int minMoves(int[] nums) {
int minVal = Arrays.stream(nums).min().getAsInt();
int sum = Arrays.stream(nums).sum();
return sum - minVal * nums.length;
}
}
总结
- Easy 题一般都在考察最基本的性质,写法是不难的,主要是想法。
- 注意:做本题的时候还需要考虑求和的结果是否会超出 int 范围,题目说「答案保证符合 32-bit 整数」,但是没有说求和的结果也是 32-bit。本题碰巧没超过而已。
——
我是 @负雪明烛 ,刷算法题 1000 多道,写了 1000 多篇算法题解,收获阅读量 300 万。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
- 在刷题的时候,如果你不知道该怎么刷题,可以看 LeetCode 应该怎么刷?
- 如果你觉得题目太多,想在短时间内快速提高,可以看 LeetCode 最经典的 100 道题。
- 公众号有更多精彩内容,点击关注。