【数学】C031_最小移动次数使数组元素相等(暴力枚举 | 优化暴力 | 数学思想)

一、题目描述

Given a non-empty integer array of size n,
find the minimum number of moves(操作) required to make all array elements equal,
where a move(动作) is incrementing n - 1 elements by 1.

Example:
Input:
[1,2,3]
Output:
3

Explanation:
Only three moves are needed (remember each move increments two elements):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

二、题解

(1) 暴力枚举(超时)

@thought:在最大元素之外执行增加,扫描数组,每次增加后,都更新最大值,又因为最大值会改变,所以,我们每次扫描都只记录本次扫描的最大值下标。

/**
 * 时间复杂度:O(n^2 k),其中 n 为数组长度,k 为最大值和最小值的差。
 * @date: 1/16/2020 7:41 PM
 * @Execution info:超时
 */
public int minMoves1(int[] nums) {
  int N = nums.length;
  int step=0;
  int minIndex=0, maxIndex=N-1;
  while (true) {
    for (int i = 0; i < N; i++) {
      if(nums[maxIndex] < nums[i])
        maxIndex = i;
      if(nums[minIndex] > nums[i])
        minIndex = i;
    }
    if(nums[maxIndex] == nums[minIndex])
      break;
    for (int i = 0; i < N; i++) {
      // 如果本次扫描的元素下标 != 最大值下标,即非最大值,而不是nums[i] != nums[maxIndex]
      if(i != maxIndex)
        nums[i]++;
    }
    step++;
  }
  return step;
}

复杂度分析

  • 时间复杂度: O(n^2 k),n^2 * 每一轮找出最大值最小值差 k 的和。

(2) 优化暴力

@thought:在minMoves1中,我们每次找到了最小值,好像并没有去很好地使用minIndex。既然,我们要让每个值都变成本次扫描的最大值,其中必然包括最小值,我们何不直接把本次扫描的最大最小值差nums[maxIndex]-nums[maxIndex]作为本次循环的加数和移动的步数呢?

/**
 * @date: 1/16/2020 8:06 PM
 * @Execution info:
 * ·执行用时  ms 击败了 % 的java用户
 * 内存消耗 MB 击败了 % 的java用户
 */
public int minMoves2(int[] nums) {
  int N = nums.length;
  int step=0;
  int minIndex=0, maxIndex=N-1;

  while(true) {
    for (int i = 0; i < N; i++) {
      if(nums[i] > nums[maxIndex])
        maxIndex = i;
      if(nums[i] < nums[minIndex])
        minIndex = i;
    }
    int diff = nums[maxIndex]-nums[minIndex];
    if(nums[minIndex] == nums[maxIndex])
      break;
    for (int i = 0; i < N; i++) {
      if(i != maxIndex)
        nums[i]+=diff;
    }
    step+=diff;
  }
  return step;
}

复杂度分析

  • 时间复杂度:O(n^2),每次迭代中两个元素是相等的。

(3) 数学思想

@thought:要让一群数字变成相等状态,可以对非最大值(即,n-1个元素)都进行进行+1操作,也等价于对每轮的最大值进行-1操作。

问题就转化为,每个非最小值数与最小值的差值

/**
 * @date: 1/16/2020 8:19 PM
 * @Execution info:
 * 执行用时 3 ms 击败了 71.8% 的java用户
 * 内存消耗 39MB 击败了 92% 的java用户
 */
public int minMoves3(int[] nums) {
  int step=0;
  int min=0x7fffffff;
//    for(int n : nums)
//      min = Math.min(n, min);
  for(int n : nums)
    if(n < min) min=n;  // 避免每次都执行不必要的赋值操作
  for(int n : nums)
    step += n-min;
  return step;
}
发布了300 篇原创文章 · 获赞 48 · 访问量 8059

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104011471
今日推荐