zoukankan      html  css  js  c++  java
  • [410. 分割数组的最大值]

    [410. 分割数组的最大值]

    给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。

    注意:
    数组长度 n 满足以下条件:

    • 1 ≤ n ≤ 1000
    • 1 ≤ m ≤ min(50, n)

    示例:

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

    思路一:

    动态规划:令 dp[i][j]为将前i个数分为j段得到的最小和。在进行状态转移时,我们可以考虑第 j 段的具体范围,即我们可以枚举 k,其中前 k 个数被分割为 j−1 段,而第 k+1 到第 i 个数为第 j 段。

    class Solution {
        public int splitArray(int[] nums, int m) {
            int n = nums.length;
            int[][] f = new int[n + 1][m + 1];
            for (int i = 0; i <= n; i++) {
                Arrays.fill(f[i], Integer.MAX_VALUE);
            }
            int[] sub = new int[n + 1];
            for (int i = 0; i < n; i++) {
                sub[i + 1] = sub[i] + nums[i];
            }
            f[0][0] = 0;
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= Math.min(i, m); j++) {
                    for (int k = 0; k < i; k++) {
                        f[i][j] = Math.min(f[i][j], Math.max(f[k][j - 1], sub[i] - sub[k]));
                    }
                }
            }
            return f[n][m];
        }
    }
    
    

    思路二:对结果进行二分查找,将当前的结果带入数组分段,确保每一段都不大于当前枚举值,如果需要的段数大于m则说明该值偏大,往前收缩,否则向后收缩。对于枚举边界l应当为Max(最大值数组和sum/段数m+0.5),r = sum

    public int splitArray(int[] nums, int m) {
        int res = Integer.MAX_VALUE;
        int l = 0, r = 0, sum = 0;
    
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            l = Math.max(l ,nums[i]);
        }
    
        l = Math.max(l, (int)(sum/m+0.5));
        r = sum;
        while (l < r){
            int n = 1;
            res = (l+r)/2;
            sum = 0;
            for (int i = 0; i < nums.length; i++) {
                if(sum + nums[i] > res){
                    sum = 0;
                    n++;
                }
                sum += nums[i];
            }
            //说明res小了
            if(n > m){
                l = res+1;
            }else {
                r = res;
            }
        }
        return l;
    }
    
    因为我喜欢追寻过程中的自己
  • 相关阅读:
    Leetcode 1489找到最小生成树李关键边和伪关键边
    Leetcode 113 路径总和 II
    hdu 1223 还是畅通工程
    hdu 1087 Super Jumping! Jumping! Jumping!
    hdu 1008 Elevator
    hdu 1037 Keep on Truckin'
    湖工oj 1241 畅通工程
    湖工oj 1162 大武汉局域网
    hdu 2057 A + B Again
    poj 2236 Wireless Network
  • 原文地址:https://www.cnblogs.com/IzuruKamuku/p/14359746.html
Copyright © 2011-2022 走看看