LeetCode 410 分割数组的最大值

题目链接

https://leetcode-cn.com/problems/split-array-largest-sum/

题目描述

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

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

示例

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

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

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

限制

1 <= nums.length <= 1000
0 <= nums[i] <= 10^6
1 <= m <= min(50, nums.length)

解题思路

对于数组的前 i i i个元素,将其划分为 j j j段的连续子数组,对于每个子数组求和,这些和的最大值表示为 m a x a max_a maxa a a a表示第 a a a种划分方法。 f [ i ] [ j ] f[i][j] f[i][j]是所有 m a x a max_a maxa中最小值。

因此可以得到以下状态转移方程:
f [ i ] [ j ] = m i n k = 0 i − 1 { m a x ( f [ k ] [ j − 1 ] , s u m { k + 1 , i } ) } f[i][j] =min_{k = 0}^{i-1}\{max( f[k][j - 1], sum\{k+1, i\} )\} f[i][j]=mink=0i1{max(f[k][j1],sum{k+1,i})}
初始化:
f [ 0 ] [ 0 ] = 0 f [ i ] [ j ] = ∞   i f   i < j   o r   ( i ! = 0   a n d   j = = 0 ) f[0][0] = 0 \\ f[i][j] = \infty \ if \ i < j \ or \ (i != 0 \ and \ j==0 ) f[0][0]=0f[i][j]= if i<j or (i!=0 and j==0)
不太好讲为什么,可以试着写一下就知道了,假设 i = j = 4 i = j = 4 i=j=4更新的时候一列一列从下往上更新

0 ∞ \infty ∞ \infty ∞ \infty ∞ \infty
∞ \infty a [ 0 ] a[0] a[0] ∞ \infty ∞ \infty ∞ \infty
∞ \infty a [ 0 ] + a [ 1 ] a[0] + a[1] a[0]+a[1] m i n { ∞ , m a x ( f [ 1 ] [ 1 ] , a [ 1 ] ) } min\{\infty, max(f[1][1], a[1])\} min{,max(f[1][1],a[1])} ∞ \infty ∞ \infty
∞ \infty a [ 0 ] + a [ 1 ] + a [ 2 ] a[0] + a[1] + a[2] a[0]+a[1]+a[2] m i n { ∞ , m a x ( f [ 1 ] [ 1 ] , a [ 1 ] + a [ 2 ] ) , m a x ( f [ 2 ] [ 1 ] , a [ 2 ] ) } min\{\infty, max(f[1][1], a[1] + a[2]), \\ max(f[2][1], a[2])\} min{,max(f[1][1],a[1]+a[2]),max(f[2][1],a[2])} m i n { ∞ , ∞ , m a x ( f [ 2 ] [ 2 ] , a [ 2 ] ) } min\{\infty,\infty,\\max(f[2][2],a[2]) \} min{,,max(f[2][2],a[2])} ∞ \infty
∞ \infty a [ 0 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] a[0] + a[1] + \\ a[2] + a[3] a[0]+a[1]+a[2]+a[3] m i n { ∞ , m a x ( f [ 1 ] [ 1 ] , a [ 1 ] + a [ 2 ] + a [ 3 ] ) , m a x ( f [ 2 ] [ 1 ] , a [ 2 ] + a [ 3 ] ) } , m a x ( f [ 3 ] [ 1 ] , a [ 3 ] ) } min\{\infty,max(f[1][1], a[1] + a[2] + a[3]), \\ max(f[2][1], a[2] + a[3])\}, max(f[3][1], a[3])\} min{,max(f[1][1],a[1]+a[2]+a[3]),max(f[2][1],a[2]+a[3])},max(f[3][1],a[3])} m i n { ∞ , ∞ , m a x ( f [ 2 ] [ 2 ] , a [ 2 ] + a [ 3 ] ) , m a x ( f [ 3 ] [ 2 ] , a [ 3 ] ) } min\{\infty, \infty, \\ max(f[2][2],a[2]+a[3]) \\,max(f[3][2],a[3]) \} min{,,max(f[2][2],a[2]+a[3]),max(f[3][2],a[3])} m i n { ∞ , ∞ , ∞ , , m a x ( f [ 3 ] [ 3 ] , a [ 3 ] ) } min\{\infty, \infty, \infty, \\, max(f[3][3], a[3]) \} min{,,,,max(f[3][3],a[3])}

Code

class Solution {
    public static int MaxValue = 1000_000_001;
    public int splitArray(int[] nums, int m) {
        int[][] dp = new int[nums.length + 1][m + 1];
        int[] sub = new int[nums.length + 1];
        
        for(int i = 0; i < nums.length + 1; i++){
            for(int j = 0; j < m + 1; j++){
                if(i < j || (i != 0 && j == 0)){
                    dp[i][j] = MaxValue; 
                    continue;
                }
                dp[i][j] = 0;
            }
        }
        int sum = 0;
        sub[0] = 0;
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
            sub[i + 1] = sum; 
        }

        for(int j = 1; j < m + 1; j++){  // 第j列
            for(int i = j; i < nums.length + 1; i++){ //第i行
                int max_value = MaxValue;
                for(int k = 0; k <= i - 1; k++){
                    int cur_sum = sub[i] - sub[k];
                    int cur_max = Math.max(dp[k][j - 1], cur_sum);
                    max_value = Math.min(cur_max, max_value);
                }
                dp[i][j] = max_value;
            }
        }
        return dp[nums.length][m];

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值