Leetcode453. 最小移动次数使数组元素相等

Leetcode453. 最小移动次数使数组元素相等

题目:
给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动可以使 n - 1 个元素增加 1。

示例:

输入:
[1,2,3]
输出:
3
解释:
只需要3次移动(注意每次移动会增加两个元素的值):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

题解:
方案一:暴力计算
时间复杂度: O ( n 2 k ) O(n^2k) :其中 n n 为数组长度, k k 为最大值和最小值的差。
空间复杂度: O ( 1 ) O(1) :不需要额外空间。
1.先循环遍历一次,找到最大值和最小值对应的数组下标;
2.如果最大值等于最小值,跳出整体循环;
3.再次循环遍历,对除了数组最大值的其他元素均加一;
4.计数器加1;
5.重复这一过程直到最大元素和最小元素相等。
方案二:暴力法优化
时间复杂度: O ( n 2 ) O(n^2) 。每次迭代中两个元素是相等的。
空间复杂度: O ( 1 ) O(1) 。不需要额外空间。
在上一方法中,每一步对每个元素增加 1。我们可以在一定程度上改进这一方法。为了让最小元素等于最大元素,至少需要加 k k 次。在那之后,最大元素可能发生变化。因此,我们一次性增加增量 k = m a x m i n k=max-min ,并将移动次数增加 k k 。然后,对整个数组进行扫描,找到新的最大值和最小值,重复这一过程直到最大元素和最小元素相等。
方案三:逆向思维
时间复杂度: O ( n ) O(n) 。对数组进行了一次遍历。
空间复杂度: O ( 1 ) O(1) 。不需要额外空间。
n 1 n-1 个数加1相当于给余下的数减1,显然,我们只需要将所有的数都减到最小的数即可, i = 0 n 1 a [ i ] n m i n ( a ) \sum_{i=0}^{n-1}a[i]-n*min(a)
方案四:逆向思维优化
时间复杂度: O ( n ) O(n) 。一次遍历寻找最小值,一次遍历计算次数。
空间复杂度: O ( 1 ) O(1) 。不需要额外空间。
上一个方法可能存在问题。 i = 0 n 1 a [ i ] \sum_{i=0}^{n-1}a[i] 可能会非常大,造成整数越界。为了避免这一问题,我们可以即时计算 i = 0 n 1 ( a [ i ] m i n ( a ) ) \sum_{i=0}^{n-1}(a[i]-min(a))
scala代码:

/**
    * 暴力法
    *
    * @param nums
    * @return
    */
  def minMoves(nums: Array[Int]): Int = {
    var count = 0
    var min = 0
    var max = nums.length - 1
    breakable(
      while (true) {
        for (i <- 0 until nums.length) {
          if (nums(i) > nums(max)) {
            max = i
          }
          if (nums(i) < nums(min)) {
            min = i
          }
        }
        if (nums(min) == nums(max)) {
          break()
        }
        for (i <- 0 until nums.length) {
          if (i != max) {
            nums(i) = nums(i) + 1
          }

        }
        count = count + 1
      }
    )
    count
  }


  /**
    * 暴力法优化
    *
    * @param nums
    * @return
    */
  def minMoves2(nums: Array[Int]): Int = {
    java.util.Arrays.sort(nums)
    var count = 0
    var min = 0
    var max = nums.length - 1
    breakable(
      while (true) {
        for (i <- 0 until nums.length) {
          if (nums(i) > nums(max)) {
            max = i
          }
          if (nums(i) < nums(min)) {
            min = i
          }
        }
        val diff = nums(max) - nums(min)
        if (diff == 0) {
          break()
        }
        count = count + diff
        for (i <- 0 until nums.length) {
          if (i != max) {
            nums(i) = nums(i) + diff
          }

        }
      }
    )
    count
  }

  /**
    * 逆向思维
    * 给n-1个数加1相当于给剩下的一个数减1
    *
    * @param nums
    * @return
    */
  def minMoves3(nums: Array[Int]): Int = {
    var count = 0
    var min = Int.MaxValue
    for (i <- 0 until nums.length) {
      count = count + nums(i)
      min = math.min(min, nums(i))
    }
    count - min * nums.length
  }

  /**
    *逆向思维优化
    * @param nums
    * @return
    */
  def minMoves4(nums: Array[Int]): Int = {
    var count = 0
    var min = Int.MaxValue
    for (i <- 0 until nums.length) {
      min = math.min(min, nums(i))
    }

    for (i <- 0 until nums.length) {
      count = count + (nums(i) - min)
    }
    count
  }
发布了112 篇原创文章 · 获赞 1 · 访问量 5979

猜你喜欢

转载自blog.csdn.net/sunhaiting666/article/details/104564472
今日推荐