LeetCode 410: Split Array Largest Sum 解题与思考
题目描述
给定一个数列{ an },以及集数m,要求在不改变{ an }中元素先后顺序的前提下,将其分成m个子集,每个子集中的数字求和,题目寻找一个分法,使得所有和中的最大值最小。
思路
万事万物皆可DP,真的
一开始想的就是将这个问题分解为两个子数列,其中一个作为一个集合,另外一边则变为求某个数列分成m-1个集合的子问题。
显然子问题有着最优子结构。
不妨假设 Rm−1,n−1 为以 a0 开头, an−1 结尾的一个数列分成m个子集所能得到的最大和的最小值,那么有递推式
Rm−1,n−1=min(maxi=0...(n−2)(Rm−2,i,∑k=i+1n−1ak))
而当m = 1时,有 R0,n−1=∑n−1k=0ak
算法
声明二维数组array[m][n]
1、初始化
array[0][q]=∑qk=0ak
2、循环计算
array[p][q]=min(max(array[p−1][i]+∑qk=i+1ak)),(i=0,1,...q−1)
3、
array[m−1][n−1]
则为所求
代码
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
int size = nums.size();
long long *arr = (long long*)malloc(sizeof(long long) * m * size);
long long sum = 0;
for ( int i = 0; i < size; i++ ) {
sum += nums[i];
arr[i] = sum;
}
for ( int i = 1; i < m; i++ ) {
for ( int j = size - 1; j >= i; j-- ) {
sum = 0;
arr[i * size + j] = 2147483999;
for ( int k = j; k >= i; k-- ) {
sum += nums[k];
long long temp = (sum < arr[(i - 1) * size + k - 1]) ? arr[(i - 1) * size + k - 1] : sum;
if ( arr[i * size + j] > temp ) arr[i * size + j] = temp;
}
}
}
int result = arr[size * m - 1];
free(arr);
return result;
}
};
思考
有个坑爹的测例:
{1, 2147483647}, m = 2
所有变量被逼无奈从int换成long long,其它的就没什么难的了