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

java代码:

   public static int minMoves(int[] nums) {
        int min = Integer.MAX_VALUE;
        for (int num : nums) {
            min = Math.min(min, num);
        }

        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            count += (nums[i] - min);
        }
        return count;
    }

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
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值