大家好,我是 @负雪明烛

解题方法:转化

转化过程

在刷题的过程中,很多题目需要通过转化变成一个更巧妙的解法,转化后效率则大大提升。

本题目为:

数组长度为 $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

  1. 计算 $nums$ 的最小值 $minVal$;
  2. 累加把 $nums$ 中每个元素降低为最小值需要的操作步骤 $num - minVal$。

算法二:求和

在算法一的基础上,我们发现累加可以转化为:

sum(nums) - minVal * N

这是一个更简洁的算法。

代码

代码一:不使用库函数

基于算法一,Python / C++ / Java 代码如下:

  1. class Solution(object):
  2. def minMoves(self, nums):
  3. minVal = float("inf")
  4. for num in nums:
  5. minVal = min(minVal, num)
  6. res = 0
  7. for num in nums:
  8. res += num - minVal
  9. return res
  1. class Solution {
  2. public:
  3. int minMoves(vector<int>& nums) {
  4. int minVal = INT_MAX;
  5. for (int num : nums) {
  6. if (num < minVal)
  7. minVal = num;
  8. }
  9. int res = 0;
  10. for (int num : nums) {
  11. res += num - minVal;
  12. }
  13. return res;
  14. }
  15. };
  1. class Solution {
  2. public int minMoves(int[] nums) {
  3. int minVal = Integer.MAX_VALUE;
  4. for (int num : nums) {
  5. if (num < minVal)
  6. minVal = num;
  7. }
  8. int res = 0;
  9. for (int num : nums) {
  10. res += num - minVal;
  11. }
  12. return res;
  13. }
  14. }

代码二:使用库函数

基于算法二,使用库函数。

Python / C++ / Java 代码如下:

  1. class Solution(object):
  2. def minMoves(self, nums):
  3. minVal = min(nums)
  4. return sum(num - minVal for num in nums)
  1. class Solution {
  2. public:
  3. int minMoves(vector<int>& nums) {
  4. int minVal = *min_element(nums.begin(), nums.end());
  5. int res = 0;
  6. for (int num : nums) {
  7. res += num - minVal;
  8. }
  9. return res;
  10. }
  11. };
  1. class Solution {
  2. public int minMoves(int[] nums) {
  3. int minVal = Arrays.stream(nums).min().getAsInt();
  4. int res = 0;
  5. for (int num : nums) {
  6. res += num - minVal;
  7. }
  8. return res;
  9. }
  10. }

代码三:基于算法二

通过库函数求和 与 最小值。

Python / C++ / Java 代码如下:

  1. class Solution(object):
  2. def minMoves(self, nums):
  3. return sum(nums) - min(nums) * len(nums)
  1. class Solution {
  2. public:
  3. int minMoves(vector<int>& nums) {
  4. int minVal = *min_element(nums.begin(), nums.end());
  5. int sum = accumulate(nums.begin(), nums.end(), 0);
  6. return sum - minVal * nums.size();
  7. }
  8. };
  1. class Solution {
  2. public int minMoves(int[] nums) {
  3. int minVal = Arrays.stream(nums).min().getAsInt();
  4. int sum = Arrays.stream(nums).sum();
  5. return sum - minVal * nums.length;
  6. }
  7. }

总结

  1. Easy 题一般都在考察最基本的性质,写法是不难的,主要是想法。
  2. 注意:做本题的时候还需要考虑求和的结果是否会超出 int 范围,题目说「答案保证符合 32-bit 整数」,但是没有说求和的结果也是 32-bit。本题碰巧没超过而已。

——
我是 @负雪明烛 ,刷算法题 1000 多道,写了 1000 多篇算法题解,收获阅读量 300 万。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。