leetcode 分割数组的最大值 困难

leetcode 分割数组的最大值 困难

 

 

 

① dp[i][j] 表示前 i 个数, 分成 j 份的各自和的最小值。

那么 dp[i][j] = min(dp[k][j - 1], pre[i] - pre[k - 1]), 其中 k ∈ [j - 2, i - 1], (前 k 个数至少保证能组成 j - 1 份)

② 二分答案,check 的时候贪心即可,一个部分的和不超过 mid 的情况下,能容纳更多元素就容纳更多元素,不能则分成一个新的部分。最后如果被分成的部分数目小于等于 m,那么这个答案是可行的。

// 二分
class Solution { public: int splitArray(const vector<int>& nums, int m) { int r = 0, l = 0; for(int i = 0; i < nums.size(); ++ i) { r += nums[i]; l = max(l, nums[i]); } int ret = -1; while(l <= r) { int mid = (l + r) >> 1; if(check(nums, mid, m)) { ret = mid; r = mid - 1; } else l = mid + 1; } return ret; } private: bool check(const vector<int> &nums, int mid, int m) { int cnt = 0, sum = 0; for(int i = 0; i < nums.size(); ++ i) { if(sum + nums[i] <= mid) { sum += nums[i]; } else { ++ cnt; sum = nums[i]; } } ++ cnt; // 最后一部分余留的 return cnt <= m; } };

 

// dp
class Solution {
public:
    int splitArray(const vector<int>& nums, int m) {
        // dp[i][j] 表示 [0, i] 数, 分成 j 份, 各自和的最小值
        vector<int> preSum;    // 前缀和, preSum[i + 1] 表示 0~i 的和
        for(int i = 0; i < nums.size(); ++ i) {
            if(i == 0) preSum.emplace_back(0);
            preSum.emplace_back(preSum.back() + nums[i]);
        }

        vector<vector<int>> dp(nums.size(), vector<int>(m + 1, INT_MAX));
        for(int i = 0; i < nums.size(); ++ i) {
            for(int j = 1; j <= m; ++ j) {
                // 前 k 个数至少组成 j - 1 份
                for(int k = j - 2; k < i; ++ k) {   // [k + 1, i] 分成一份, preSum[i] - preSum[k], 然后做 1 个单位偏移量
                    if(k == -1) {   // [0, i] 成一组
                        dp[i][j] = preSum[i + 1] - preSum[k + 1];
                        continue;
                    }
                    dp[i][j] = min(dp[i][j], max(dp[k][j - 1], preSum[i + 1] - preSum[k + 1]));
                }
            }
        }
        return dp.back().back();
    }
};

 

上一篇:《Java和Android开发实战详解》——1.2节Java基础知识


下一篇:python 前缀和总结