Leetcode 410 - Split Array Largest Sum(dp or 二分答案)

66 篇文章 0 订阅
27 篇文章 0 订阅

题意

给定一个数组,将数组划分m组,要求每组的和的最大值最小

思路

算法1:dp

首先我们这样考虑:我们要将前n个元素划分成m段,即先找一个划分点k,在[k + 1, n]不再划分。然后将[1, k]划分成m - 1段。那么就可以得到我们的状态表示和转移方程。

状态表示 d[i,j] ,前i个元素,划分成j段的最大和。
转移方程 d[i,j]=min{max0k<i{d[k,j1]},p=k+1jap}
时间复杂度 O(n2m)

算法2:二分

最大值最小问题一般采用二分答案的方法。

我们二分一下我们最后的答案,判断答案是否合法即可。
判断数x是否合法:统计一下将数组划分为最大值 x 时能划分多少组。如果组数 cnt>x ,则说明我们答案应该更大,否则,答案可以减小。

代码

//algorithm 1: dp
const int maxn = 1005;
const int maxm = 55;
int d[maxn][maxm];

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        int n = nums.size();
        if (n == 0) return 0;
        int S[maxn]; S[0] = nums[0];
        for (int i = 1; i < n; i++) S[i] = S[i - 1] + nums[i];
        for (int i = 0; i < n; i++) d[i][1] = S[i];
        for (int j = 2; j <= m; j++) {
            for (int i = 0; i < n; i++) {
                d[i][j] = INT_MAX;
                for (int k = 0; k < i; k++) 
                    d[i][j] = min(d[i][j], max(d[k][j - 1], S[i] - S[k]));
            }
        }
        return d[n - 1][m];
    }
};

//algorithm 2: Binary Search
class Solution {
public:
    bool judge(long long x, int m, vector<int> nums) {
        int cnt = 0;
        bool f = false;
        long long sum = 0;
        for (int i = 0; i < nums.size(); i++) {
            if ((long long)nums[i] > x) return false;
            sum += nums[i];
            if (i == nums.size() - 1) {
                if (sum > x) cnt += 2;
                else cnt++;
            } else {
                if (sum > x) {
                    cnt++;
                    sum = nums[i];
                }
            }
        }
        if (cnt > m) return false;
        return true;
    }

    int splitArray(vector<int>& nums, int m) {
        int n = nums.size();
        if (n == 0) return 0;
        long long sum = nums[0], MIN = nums[0];
        for (int i = 1; i < n; i++) {sum += nums[i]; MIN = min(MIN, (long long)nums[i]);}
        long long L = MIN, R = sum, M = L + (R - L) / 2, res = sum;
        while (L < R) {
            if (R == L + 1) {
                if (judge(L, m, nums)) M = L;
                else M = R;
                break;    
            }
            M = L + (R - L) / 2;
            if (judge(M, m, nums)) R = M;
            else L = M;
        }
        return M;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值