813. Largest Sum of Averages
leetcode
Task
: medium
Вам дан целочисленный массив nums и целое число k. Вы можете разбить массив на не более чем k непустых смежных подмассивов. Оценка разбиения равна сумме средних значений каждого подмассива.
Обратите внимание, что при разбиении должны быть использованы все целые числа из nums, и что оценка не обязательно является целым числом.
Верните максимальную оценку, которую можно достичь среди всех возможных разбиений. Ответы, отличающиеся от фактического ответа не более чем на 10^-6, будут приняты.
Пример:
Input: nums = [9,1,2,3,9], k = 3
Output: 20.00000
Explanation:
The best choice is to partition nums into [9], [1, 2, 3], [9]. The answer is 9 + (1 + 2 + 3) / 3 + 9 = 20.
We could have also partitioned nums into [9, 1], [2], [3, 9], for example.
That partition would lead to a score of 5 + 2 + 6 = 13, which is worse.
C# solution
matched/originalusing System;
public class Solution {
public double LargestSumOfAverages(int[] A, int K) {
int N = A.Length;
double[] P = new double[N + 1];
// Префиксные суммы
for (int i = 0; i < N; ++i)
P[i + 1] = P[i] + A[i];
double[] dp = new double[N];
for (int i = 0; i < N; ++i)
dp[i] = (P[N] - P[i]) / (N - i);
for (int k = 0; k < K - 1; ++k) {
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
dp[i] = Math.Max(dp[i], (P[j] - P[i]) / (j - i) + dp[j]);
}
}
}
return dp[0];
}
}C++ solution
auto-draft, review before submit#include <bits/stdc++.h>
using namespace std;
// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
public double LargestSumOfAverages(vector<int>& A, int K) {
int N = A.size();
double[] P = new double[N + 1];
// Префиксные суммы
for (int i = 0; i < N; ++i)
P[i + 1] = P[i] + A[i];
double[] dp = new double[N];
for (int i = 0; i < N; ++i)
dp[i] = (P[N] - P[i]) / (N - i);
for (int k = 0; k < K - 1; ++k) {
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
dp[i] = max(dp[i], (P[j] - P[i]) / (j - i) + dp[j]);
}
}
}
return dp[0];
}
}Java solution
matched/originalclass Solution {
public double largestSumOfAverages(int[] A, int K) {
int N = A.length;
double[] P = new double[N + 1];
for (int i = 0; i < N; ++i)
P[i + 1] = P[i] + A[i];
double[][] dp = new double[N][N];
for (int i = 0; i < N; ++i)
dp[i][0] = (P[N] - P[i]) / (N - i);
for (int k = 0; k < K - 1; ++k) {
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
dp[i][0] = Math.max(dp[i][0], (P[j] - P[i]) / (j - i) + dp[j][0]);
}
}
}
return dp[0][0];
}JavaScript solution
matched/originalvar largestSumOfAverages = function(A, K) {
const N = A.length;
const P = new Array(N + 1).fill(0);
for (let i = 0; i < N; i++) {
P[i + 1] = P[i] + A[i];
}
const dp = new Array(N).fill(0);
for (let i = 0; i < N; i++) {
dp[i] = (P[N] - P[i]) / (N - i);
}
for (let k = 0; k < K - 1; k++) {
for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
dp[i] = Math.max(dp[i], (P[j] - P[i]) / (j - i) + dp[j]);
}
}
}
return dp[0];Go solution
matched/originalfunc largestSumOfAverages(A []int, K int) float64 {
N := len(A)
P := make([]float64, N+1)
for i := 0; i < N; i++ {
P[i+1] = P[i] + float64(A[i])
}
dp := make([]float64, N)
for i := 0; i < N; i++ {
dp[i] = (P[N] - P[i]) / float64(N-i)
}
for k := 0; k < K-1; k++ {
for i := 0; i < N; i++ {
for j := i+1; j < N; j++ {
dp[i] = max(dp[i], (P[j] - P[i]) / float64(j-i) + dp[j])
}
}
}
return dp[0]
}
func max(a, b float64) float64 {
if a > b {
return a
}
return b
}Explanation
Algorithm
Пусть dp(i, k) будет лучшей оценкой для разбиения массива A[i:] на не более чем k частей. Если первая группа, в которую мы разбиваем A[i:], заканчивается перед j, тогда наше разбиение-кандидат имеет оценку average(i, j) + dp(j, k-1), где average(i, j) = (A[i] + A[i+1] + ... + A[j-1]) / (j - i) (деление с плавающей запятой). Мы берем наивысшую оценку из этих вариантов, помня, что разбиение необязательно - dp(i, k) также может быть просто average(i, N).
В общем случае наша рекурсия выглядит так: dp(i, k) = max(average(i, N), max_{j > i}(average(i, j) + dp(j, k-1))). Мы можем рассчитывать average немного быстрее, используя префиксные суммы. Если P[x+1] = A[0] + A[1] + ... + A[x], тогда average(i, j) = (P[j] - P[i]) / (j - i).
Наша реализация демонстрирует подход "снизу вверх" для динамического программирования. На шаге k во внешнем цикле, dp[i] представляет собой dp(i, k) из обсуждения выше, и мы рассчитываем следующий слой dp(i, k+1). Завершение второго цикла для i = 0..N-1 означает завершение расчета правильного значения для dp(i, t), а внутренний цикл выполняет расчет max_{j > i}(average(i, j) + dp(j, k)).
😎