日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[Leetcode][第410题][JAVA][分割数组的最大值][动态规划][二分]

發布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Leetcode][第410题][JAVA][分割数组的最大值][动态规划][二分] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【問題描述】[中等]

【解答思路】

1. 動態規劃

第 1 步:設計狀態
令 f[i][j] 表示將數組的前 i 個數分割為 j 段所能得到的最大連續子數組和的最小值。 ( i ≥ j )
第 2 步:狀態轉移方程

第 3 步:考慮初始化
f[i][j] = Integer.MAX_VALUE
f[0][0]=0
第 4 步:考慮輸出
f[n][m]f[n][m]

復雜度

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];} }
2. 二分+貪心


nums = [7,2,5,10,8]
m = 1,那么整個數組作為一部分,最小的最大值為 32
m = n,那么每個元素作為一個子數組,從所有元素選取最大值,最小的最大值小為 10
m 的取值范圍為 1 <= m <= n,因此,最大值的最小值的范圍為 [10, 32]
我們利用二分法查找,找出符合 m 的最大值的最小的結果
二分過程:
left = 10;
right = 32
mid = (left + right) >>> 1 = 21(這個 21 就是一個子數組的最大容量)
我們假設剛開辟的用來存儲的子數組個數 cnt = 1
那么根據貪心思想,我們將數組元素按順序逐個往里放
因此就有如下過程:
7 < 21
7 + 2 < 21
7 + 2 + 5 < 21
7 + 2 + 5 + 10 > 21
至此,我們可以看出一個 21 容量的子數組是無法容納整個數組元素的,因此我們需要開辟第二個子數組來存儲剩下的數組元素
cnt = cnt + 1 = 2
10 < 21
10 + 8 < 21
我們發現,兩個子數組可以將整個數組元素放入,而 cnt 剛好等于 m,因此 [7,2,5] 和 [10,8] 就是分割出來的兩個子數組,最小的最大值為 18

區間縮小 (建議在草稿紙上模擬過程)

  • [10.31]
  • [10.21]
  • [16,21]
  • [16,18]
  • [17.18]
  • [18.18]
  • 為什么是放入元素直到放不下為止?因為要求的是連續子數組,我們需要保證每個連續的子數組的元素和都盡可能的接近 21

    如果我們最終得到的 cnt > m,那么表示我們劃分出太多的子數組,也就是意味著一個子數組的容量太少,我們需要再擴大容量,即 left = mid + 1,然后繼續進行二分
    如果我們最終得到的 cnt < m,那么表示我們劃分出太少的子數組,也就是意味著一個子數組的容量太大,需要減少容量,即 right = mid

    復雜度

    public class Solution {public int splitArray(int[] nums, int m) {int max = 0;int sum = 0;// 計算「子數組各自的和的最大值」的上下界for (int num : nums) {max = Math.max(max, num);sum += num;}// 使用「二分查找」確定一個恰當的「子數組各自的和的最大值」,// 使得它對應的「子數組的分割數」恰好等于 mint left = max;int right = sum;while (left < right) {int mid = left + (right - left) / 2;int splits = split(nums, mid);if (splits > m) {// 如果分割數太多,說明「子數組各自的和的最大值」太小,此時需要將「子數組各自的和的最大值」調大// 下一輪搜索的區間是 [mid + 1, right]left = mid + 1;} else {// 下一輪搜索的區間是上一輪的反面區間 [left, mid]right = mid;}}return left;}/***** @param nums 原始數組* @param maxIntervalSum 子數組各自的和的最大值* @return 滿足不超過「子數組各自的和的最大值」的分割數*/private int split(int[] nums, int maxIntervalSum) {// 至少是一個分割int splits = 1;// 當前區間的和int curIntervalSum = 0;for (int num : nums) {// 嘗試加上當前遍歷的這個數,如果加上去超過了「子數組各自的和的最大值」,就不加這個數,另起爐灶if (curIntervalSum + num > maxIntervalSum) {curIntervalSum = 0;splits++;}curIntervalSum += num;}return splits;}public static void main(String[] args) {int[] nums = new int[]{7, 2, 5, 10, 8};int m = 2;Solution solution = new Solution();int res = solution.splitArray(nums, m);System.out.println(res);} }

    【總結】

    1. 動態規劃流程

    第 1 步:設計狀態
    第 2 步:狀態轉移方程
    第 3 步:考慮初始化
    第 4 步:考慮輸出
    第 5 步:考慮是否可以狀態壓縮

    2.細節

    Arrays.fill()并不能提高賦值的效率,在函數的內部也是用for循環的方式 實現的。
    fill()函數源碼:

    public static void fill(Object[] a, Object val) {for (int i = 0, len = a.length; i < len; i++)a[i] = val;} for (int i = 0; i <= n; i++) {Arrays.fill(f[i], Integer.MAX_VALUE);}

    等價于

    for (int i = 0; i <= n; i++) {for(int j =0 ;j<=m;j++){f[i][j] = Integer.MAX_VALUE;}}
    3.審題認真! Java函數不懂可以看源碼, 效率超高!(總比瞎猜好)

    參考鏈接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/er-fen-cha-zhao-by-liweiwei1419-4/
    參考鏈接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/fen-ge-shu-zu-de-zui-da-zhi-by-leetcode-solution/

    總結

    以上是生活随笔為你收集整理的[Leetcode][第410题][JAVA][分割数组的最大值][动态规划][二分]的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。