开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
前言
小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标1900分,现在1806!!
11月28日每日一题
813. 最大平均值和的分组
给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个相邻的非空子数组 。 分数 由每个子数组内的平均值的总和构成。
注意我们必须使用 nums 数组中的每一个数进行分组,并且分数不一定需要是整数。
返回我们所能得到的最大 分数 是多少。答案误差在 10-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 <= nums.length <= 1001 <= nums[i] <= 1041 <= k <= nums.length
代码
长度100,本以为可以用递归搜索,结果好像不太行,代码如代码一,下面这个示例过不去,但是如果面试手撕的时候,可以两个方法都试试,应该会是加分项。
[4663,3020,7789,1627,9668,1356,4207,1133,8765,4649,205,6455,8864,3554,3916,5925,3995,4540,3487,5444,8259,8802,6777,7306,989,4958,2921,8155,4922,2469,6923,776,9777,1796,708,786,3158,7369,8715,2136,2510,3739,6411,7996,6211,8282,4805,236,1489,7698] 27
解法一(递归)
class Solution {
double max = 0;
public double largestSumOfAverages(int[] nums, int k) {
max = 0;
dfs(nums, k, 0, 0, 0);
return max;
}
//index 是组 have是序号
private void dfs(int[] nums, int k, int index, int have, double res) {
if (have == nums.length) {
if (index == k) {
max = Math.max(max, res);
}
return;
}
if (index > k) {
return;
}
double temp = 0;
for (int i = have; i < nums.length; i++) {
temp = temp + nums[i];
dfs(nums, k, index + 1, i + 1, res + temp / (i - have + 1));
}
}
}
解法二(dp)
dp[i][k] 表示将前i个数,分为k组
dp[i][j] 如果的更新是由dp[a][j - 1] a从0到i-1,加上a到i分为一组的平均值
- dp[i][j] = Math.max(dp[i][j], dp[l][j - 1] + (preSum[i+1] - preSum[l+1]) / (i - l));
经典dp做法。
class Solution {
public double largestSumOfAverages(int[] nums, int k) {
double[][] dp = new double[nums.length][k + 1];
double[] preSum = new double[nums.length + 1];
for (int i = 0; i < nums.length; i++) {
preSum[i + 1] = preSum[i] + nums[i]; //presum[i] = num[0] +++num[i - 1]
dp[i][1] = preSum[i + 1] / (i + 1);
}
for (int i = 1; i < nums.length; i++) {
for (int j = 2; j <= k; j++) {
for (int l = 0; l < i; l++) {
dp[i][j] = Math.max(dp[i][j], dp[l][j - 1] + (preSum[i+1] - preSum[l+1]) / (i - l));
}
}
}
return dp[nums.length - 1][k];
}
}