410. Split Array Largest Sum

410. Split Array Largest Sum


Given an array which consists of non-negative integers and an integer m, you can split the array into m non-empty continuous subarrays. Write an algorithm to minimize the largest sum among these m subarrays.

Note:
If n is the length of array, assume the following constraints are satisfied:

1 ≤ n ≤ 1000
1 ≤ m ≤ min(50, n)
Examples:

Input:
nums = [7,2,5,10,8]
m = 2

Output:
18

Explanation:

  1. There are four ways to split nums into two subarrays.
  2. The best way is to split it into [7,2,5] and [10,8],
  3. where the largest sum among the two subarrays is only 18.

方法1: dynamic programming

思路:

首先这种寻找最佳切法的题目,一般都可以一步一步缩小成子问题,当找到子问题的最优后,再思考如何再size增加时找到下一步最优解。在这道题里,有两种缩小问题的方向,第一是vector长度可能缩小,第二是m可以缩小。先看第一种,对与[0, j]范围内的vector,m的最优解如何得到?我们只需要考虑如何切最后一段,遍历所有可能切的位置,每一次算出最后一段的sum,和之前一段切m - 1段的最优解进行max比较,就是这种切法不得不承受的max。而遍历所有切的位置取的min,就是[0, j]内切m段能获得的min max sum。

这里令人头秃的三重循环各自含义如下:
i : 需要切的段数
j : 整体字符串长度
k:最后一切的前一个位置,也就是切成[0,…,k], [k + 1, j]的样子

vector<vector<\int>> dp(m, vector<\int>(n + 1, INT_MAX)): 这里按理说第一行存成presum就可以,也就是m = 1时的dp解。但是由于要取最小值,初始化成INT_MAX就不能用来累计presum了,会overflow,借助一个单独的presum来完成。
initialiaztion:INT_MAX, 第一行为presum,第一列是0。
transfer:尝试每一个最后一切的位置k,dp[i][j] = min(dp[i][j], max(dp[i - 1][k], dp[0][j] - dp[0][k]);
return: dp.back().back()

Complexity

Time complexity: O(m * n ^ 2)
Space complexity: O(m * n)

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        int n = nums.size();
        if (n == m) return *max_element(begin(nums), end(nums));
        vector<vector<int>> dp(m, vector<int>(n + 1, INT_MAX));
        vector<int> presum(n + 1, 0);
        for (int j = 1; j < n + 1; j++) {
            presum[j] = presum[j - 1] + nums[j - 1];
            dp[0][j] = presum[j];
        }
        for (int i = 0; i < m; i++) dp[i][0] = 0;
        
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n + 1; j++) {
                for (int k = i - 1; k < j; k++) {
                    dp[i][j] = min(dp[i][j], max(dp[i - 1][k], dp[0][j] - dp[0][k]));
                }
            }
        }
        return dp.back().back(); 
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值