leetcode 410 分割陣列的最大值
阿新 • • 發佈:2020-07-25
package com.example.lettcode.dailyexercises; import java.util.Arrays; /** * @Class SplitArray * @Description 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,在所有情況中最小。 * @Author * @Date 2020/7/25 **/ public class SplitArray { }
/** * 方法1:利用動態規劃: * 狀態表示 dp[i][j] 表示nums[0..i]劃分成j段時的最大值 * 狀態轉移:dp[i][j] 為0~i的前k個位置被分成了j-1段,然後最後一個部分的值是sub[i]-sub[j] * 其中sub[i] 是前i個nums元素的值 * 初始條件:dp[0][0]=0 */ public static int splitArray(int[] nums, int m) { if (nums == null || nums.length < m) return -1; int n = nums.length; // dp[i][j] 表示nums[0..i]劃分成j段時的最小情況 int[][] dp = new int[n + 1][m + 1]; for (int i = 0; i <= n; i++) { Arrays.fill(dp[i], Integer.MAX_VALUE); } // sub[i]表示num[0..i]的和 int[] sub = new int[n + 1]; for (int i = 0; i < n; i++) { sub[i + 1] = sub[i] + nums[i]; } // 初始條件 dp[0][0] = 0; for (int i = 1; i <= n; i++) { // 由於我們不能分出空的子陣列,所以必須有i>=j for (int j = 1; j <= Math.min(i, m); j++) { // nums的前k-1個數被分為j-1段,然後nums(k~i)為第j段 // k為啥可以從0開始還沒理解 2020/07/25 for (int k = 0; k < i; k++) { // 狀態轉移方程 dp[i][j] = Math.min(dp[i][j], Math.max(dp[k][j - 1], sub[i] - sub[k])); } } } return dp[n][m]; }
/** * 解法2:利用二分查詢+貪心 * 這是哪位大神想出來的方法 */ public static int splitArray(int[] nums, int m) { int left = 0, right = 0; for (int i = 0; i < nums.length; i++) { right += nums[i]; if (left < nums[i]) { left = nums[i]; } } while (left < right) { int mid = (right - left) / 2 + left; if (check(nums, mid, m)) { right = mid; } else { left = mid + 1; } } return left; } // 這個意思是將nums進行劃分時,保證每個連續子陣列之和不超過x ,採用這種方式劃分對應的子陣列個數不是否超過m // 劃分時,從左到右逐個元素相加,與當前元素之和超過x時,說明需要新劃分一個子陣列,以此類推,判斷最終 // 可以劃分的組數 public static boolean check(int[] nums, int x, int m) { int sum = 0; int cnt = 1; for (int i = 0; i < nums.length; i++) { if (sum + nums[i] > x) { cnt++; sum = nums[i]; } else { sum += nums[i]; } } return cnt <= m; }
// 測試用例
public static void main(String[] args) {
int[] nums = new int[]{7, 2, 5, 10, 8};
int m = 2;
int ans = splitArray(nums, m);
System.out.println("SplitArray demo01 result:" + ans);
}