题解 | #小美的数组操作#

小美的数组操作

https://ac.nowcoder.com/acm/problem/258420

问题分析

  • 关键信息: 根据题目要求,我们需要以最少操作次数构造出最多数量的众数。其中「最多数量的众数」是优先的,即优先让数量更多,再考虑最少操作次数;
  • 平均值: 题目操作可以分别对两个数加一和减一,最优情况下数组元素和能够被 n 整除时,能够构造最大众数。
  • 局部平均: 如果无法构造完全平均,当选择一个数作为工具数,一定可以保证其他 n - 1 个数是平均的。此时,问题的关键在于选择哪些数(哪个数作为工具数)以及选哪个目标平均值。
1   | 123456
4   | 333333
-2  | 444444
...
-32 | 999999
  • 中位数: 为了让操作数尽可能小,选择 n - 1 个数的平均值作为目标值是最优的。当不能整除时,要考虑左中位数和右中位数两种情况。
  • 贡献度: 数组的最大值和最小值对平均值的贡献度是最大的,相应地也需要更多操作数,所以我们只需要考虑将最大值和最小值作为工具数的情况。
fun main(args: Array<String>) {
    val n = nextInt()
    val nums = nextArrayI(n)
    var fullSum = nums.fold(0L) { it, arr -> it + arr }

    fun count(nums: IntArray, from: Int, to: Int, target: Long): Long {
        var c0 = 0L
        var c1 = 0L
        for (i in from..to) {
            if (nums[i] < target) {
                c0 += target - nums[i]
            } else {
                c1 += nums[i] - target
            }
        }
        return max(c0, c1)
    }

    if (fullSum % n == 0L) {
        // 全局平均
        println(count(nums, 0, n - 1, fullSum / n))
    } else {
        // 局部平均
        nums.sort()
        val target1 = (fullSum - nums[0]) / (n - 1)
        val target2 = (fullSum - nums[n - 1]) / (n - 1)
        val choice1 = min(count(nums, 1, n - 1, target1), count(nums, 1, n - 1, target1 + 1))
        val choice2 = min(count(nums, 0, n - 2, target2), count(nums, 0, n - 2, target2 + 1))
        println(min(choice1, choice2))
    }
    done()
}

也可以提前判断取左中位数还是右中位数:

fun main(args: Array<String>) {
    val n = nextInt()
    val nums = nextArrayI(n)
    var fullSum = nums.fold(0L) { it, arr -> it + arr }
		...
    if (fullSum % n == 0L) {
        // 全局平均
        println(count(nums, 0, n - 1, fullSum / n))
    } else {
        // 局部平均
        nums.sort()
        // 选择 1
        var target1 = (fullSum - nums[0]) / (n - 1)
        if ((fullSum - nums[0]) % (n - 1) > (n - 1) / 2) target1++
        val count1 = count(nums, 1, n - 1, target1)
        // 选择 2
        var target2 = (fullSum - nums[n - 1]) / (n - 1)
        if ((fullSum - nums[n - 1]) % (n - 1) > (n - 1) / 2) target2++
        val count2 = count(nums, 0, n - 2, target2)
        println(min(count1, count2))
    }
    done()
}

复杂度分析:

  • 时间复杂度:O(nlgn) 瓶颈在排序;
  • 空间复杂度:O(n) nums 数组空间。
全部评论

相关推荐

点赞 评论 收藏
转发
1 1 评论
分享
牛客网
牛客企业服务