【LeetCode】410. 分割数组的最大值

文章目录

  • 题目:410. 分割数组的最大值
  • 解题思路-二分法
    • 思路-二分法
    • 步骤
  • 代码

题目:410. 分割数组的最大值

410. 分割数组的最大值


给定一个非负整数数组nums和一个整数m,你需要将这个数组分成m个非空的连续子数组。

设计一个算法使得这 m个子数组各自和的最大值最小。

示例 1:

输入:nums = [7,2,5,10,8], m = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

示例 2:

输入:nums = [1,2,3,4,5], m = 2
输出:9

示例 3:

输入:nums = [1,4,4], m = 3
输出:4

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 106
  • 1 <= m <= min(50, nums.length)

解题思路-二分法

思路-二分法

通过题干给出的非负整数数组、非空、连续,可以考虑使用二分法解决问题。

  • 如果设置【数组各自和的最大值】很大,必然导致分割数很小
  • 如果设置【数组各自和的最大值】很小,必然导致分割数很大
    所以可以通过调整【数组各自和的最大值】来达到使分割数等于m的效果。

注意:
如果某个【数组各自和的最大值】恰好使分割数为m,此时不能放弃搜索,因为要使这个最大值最小化。此时还应该继续缩小这个【数组各自和的最大值】,使分割数超过m,最后一个使分割数为m的值就是要求的最小值


举例:
如题:[7, 2, 5, 10, 8], m = 2

  • 设置【数组各自和最大值】为21,分隔为[7, 2, 5, | 10, 8]]m = 2
  • 设置【数组各自和最大值】为20,分隔为[7, 2, 5, | 10, 8]]m = 2
  • 设置【数组各自和最大值】为19,分隔为[7, 2, 5, | 10, 8]]m = 2
  • 设置【数组各自和最大值】为18,分隔为[7, 2, 5, | 10, 8]]m = 2
  • 设置【数组各自和最大值】为17,分隔为[7, 2, 5, | 10, | 8]]m = 3

所以18是问题的最小值

步骤

  1. 设置minSummaxSum,求出【子数组各自和的最大值】的上下界(数组中的最大元素和数组总和),分别对应二分法leftright的初始值
  2. 构造求分割数的函数:
    1. 遍历数组,叠加元素,如果超出了当前界限,分割数+1;
  3. 二分法
    1. 求出mid,作为分隔的界限,求出分割数
    2. 如果分割数大于m,说明【子数组各自和的最大值】太小,缩小下界限
    3. 否则缩小上界限
  4. 返回下界

代码

class Solution {
public:
// 1. 设置`minSum`和`maxSum`,求出【子数组各自和的最大值】的上下界(数组中的最大元素和数组总和),分别对应二分法`left`和`right`的初始值
// 2. 构造求分割数的函数:
// 	1. 遍历数组,叠加元素,如果超出了当前界限,分割数+1;
// 3. 二分法
// 	1. 求出`mid`,作为分隔的界限,求出分割数
// 	2. 如果分割数大于`m`,说明【子数组各自和的最大值】太小,缩小下界限
// 	3. 否则缩小上界限
// 4. 返回下界
    int split(vector<int>& nums, int mid) {
        int split = 1, sum = 0;
        for (int num:nums) {
            if (sum + num > mid) {
                sum = 0;
                split++;
            }
            sum += num;
        }
        return split;
    }
    int splitArray(vector<int>& nums, int m) {
        int minSum = 0, maxSum = 0;
        for (int num:nums) {
            minSum = max(minSum, num);
            maxSum += num;
        }

        int left = minSum, right = maxSum;
        while (left < right) {
            int mid = left + (right - left) / 2;
            int splits = split(nums, mid);
            if (splits > m) left = mid + 1;
            else right = mid;
        }
        return left;

    }
};

你可能感兴趣的:(算法笔记,leetcode,算法,动态规划)