LeetCode 每日 1 题:最大平均值和的分组

119 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 2 天,点击查看活动详情

最大平均值和的分组

原题地址

给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个相邻的非空子数组 。 分数 由每个子数组内的平均值的总和构成。

注意我们必须使用 nums 数组中的每一个数进行分组,并且分数不一定需要是整数。

返回我们所能得到的最大 分数 是多少。答案误差在 10610^{-6} 内被视为是正确的。

示例 1:

输入: nums = [9,1,2,3,9], k = 3
输出: 20.00000
解释: 
nums 的最优分组是[9], [1, 2, 3], [9]. 得到的分数是 9 + (1 + 2 + 3) / 3 + 9 = 20. 
我们也可以把 nums 分成[9, 1], [2], [3, 9]. 
这样的分组得到的分数为 5 + 2 + 6 = 13, 但不是最大值.

示例 2:

输入: nums = [1,2,3,4,5,6,7], k = 4
输出: 20.50000

提示:

  1. 1 <= nums.length <= 100
  2. 1 <= nums[i] <=10410^4
  3. 1 <= k <= nums.length

思路分析

  1. 题目要求算区间内的平均值,因此需要知道区间内元素的和,定义 sum 来存储和,sum[i] 表示前i项的和;
  2. 定义函数 find 返回对区间 [left, right] 切分成 n 段的最大结果值;对于每个区间,将区间划分为 [left, i][i+1, right] 两个部分,记 val(left, right)[left, right] 的平均值,则 find(left, right, n) = val(left, i) + find(i+1, right, n-1)
  3. 定义 getSum 来计算区间 [left, right] 内的平均值;
  4. 定义 getFlag 来计算一个唯一的 flag 标识;
  5. 在遍历过程中,将 flag 作为key值来存储平均值,然后每次给 res 赋值 Math.max(res, getSum(left, i) + find(i + 1, right, n - 1)) 的最大值,最后返回 res 即可。

AC 代码

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var largestSumOfAverages = function(nums, k) {
    // 递归
    let sum = [] // 前缀和数组
    let s = 0
    let map = new Map()
    for (let i of nums) {
        s += i
        sum.push(s)
    }

    function getSum(left, right) { // 获取区间内的平均值
        let len = right - left + 1
        return left === 0 ? sum[right] / len : (sum[right] - sum[left - 1]) / len
    }

    function getFlag(left, right, n) {
        let p = 857
        return left * p * p + right * p + n
    }

    function find(left = 0, right = nums.length - 1, n = k) {
        if (n === 1) return getSum(left, right)
        let flag = getFlag(left, right, n)
        if (map.has(flag)) return map.get(flag)
        let res = 0
        for (let i = left; right - i >= n-1; i++) {
            res = Math.max(res, getSum(left, i) + find(i + 1, right, n - 1))
        }
        map.set(flag, res)
        return res
    }

    return find()
};

结果:

  • 执行结果: 通过
  • 执行用时:64 ms, 在所有 JavaScript 提交中击败了91.67%的用户
  • 内存消耗:42.9 MB, 在所有 JavaScript 提交中击败了83.33%的用户
  • 通过测试用例:51 / 51

END