1. 程式人生 > 其它 >【Leetcode】1335. Minimum Difficulty of a Job Schedule

【Leetcode】1335. Minimum Difficulty of a Job Schedule

技術標籤:LC 貪心、動態規劃與記憶化搜尋動態規劃leetcode演算法java

題目地址:

https://leetcode.com/problems/minimum-difficulty-of-a-job-schedule/

給定一個長 n n n正整數陣列 A A A和一個正整數 d d d,要求將 A A A分為 d d d個非空子陣列,使得每個子陣列的最大值加起來最小。返回那個最小和。如果不存在切割方案,則返回 − 1 -1 1

可以用動態規劃。首先,如果 n < d n<d n<d,那麼不存在切割方案,則返回 − 1 -1 1。設 f [ k ] [ i ] f[k][i]

f[k][i] A [ i : n − 1 ] A[i:n-1] A[i:n1]被切成 k k k個非空子陣列的情況下,子陣列最大值的最小和是多少。那麼 f [ 1 ] [ i ] = max ⁡ A [ i : n − 1 ] f[1][i]=\max A[i:n-1] f[1][i]=maxA[i:n1],並且 f [ k ] [ i ] = min ⁡ i ≤ j ≤ n − k { max ⁡ A [ i : j ] + f [ k − 1 ] [ j + 1 ] } f[k][i]=\min_{i\le j\le n-k}\{\max A[i:j]+f[k-1][j+1]\}
f[k][i]=ijnkmin{maxA[i:j]+f[k1][j+1]}
這裡 n − k ≥ j n-k\ge j nkj的原因是, A [ j + 1 : n − 1 ] A[j+1:n-1] A[j+1:n1]必須長度大於等於 k − 1 k-1 k1才夠切出 k − 1 k-1 k1個子陣列。程式碼如下:

import java.util.Arrays;

public class Solution {
    public int minDifficulty(int[] A, int d) {
        int n = A.length;
        if
(n < d) { return -1; } // 初始化為正無窮 int[][] dp = new int[d + 1][n]; for (int[] row : dp) { Arrays.fill(row, 1 << 30); } // 求一下dp[1] for (int i = n - 1, curMax = 0; i >= 0; i--) { curMax = Math.max(curMax, A[i]); dp[1][i] = curMax; } for (int i = 2; i <= d; i++) { for (int j = 0; j <= n - i; j++) { int curMax = 0; for (int k = j; k <= n - i; k++) { curMax = Math.max(curMax, A[k]); dp[i][j] = Math.min(dp[i][j], curMax + dp[i - 1][k + 1]); } } } return dp[d][0]; } }

時間複雜度 O ( d n 2 ) O(dn^2) O(dn2),空間 O ( d n ) O(dn) O(dn)

可以考慮滾動陣列優化:

import java.util.Arrays;

public class Solution {
    public int minDifficulty(int[] A, int d) {
        int n = A.length;
        if (n < d) {
            return -1;
        }
        
        int[][] dp = new int[2][n];
        for (int i = n - 1, curMax = 0; i >= 0; i--) {
            curMax = Math.max(curMax, A[i]);
            dp[1][i] = curMax;
        }
        
        for (int i = 2; i <= d; i++) {
        	// 將要計算的那一行初始化為正無窮
            Arrays.fill(dp[i & 1], 1 << 30);
            for (int j = 0; j <= n - i; j++) {
                int curMax = 0;
                for (int k = j; k <= n - i; k++) {
                    curMax = Math.max(curMax, A[k]);
                    dp[i & 1][j] = Math.min(dp[i & 1][j], curMax + dp[i - 1 & 1][k + 1]);
                }
            }
        }
        
        return dp[d & 1][0];
    }
}

時間複雜度不變,空間 O ( n ) O(n) O(n)