【leetcode/二分】分割數組的最大值(二分+貪心)

問題描述:

給定一個非負整數數組和一個整數 m,你需要將這個數組分成 個非空的連續子數組。設計一個算法使得這 個子數組各自和的最大值最小。

注意:
數組長度 滿足以下條件:

  • 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,在所有情況中最小。

基本思路:

leetcode上難度爲困難的題目。用到了很巧妙的二分思想

以前我們的二分都是在已有的數組中尋找元素,這裏的二分則不同。

它是預測你的連續子數組的最大值,來分隔你的數組。根據分割的結果+二分的思想來重新預測。

代碼上看十分簡單。

這體現了二分的本質:預測+修改預測。這個預測不一定要是數組中的索引啊啥的,可以是像本題中的元素的和。

AC代碼:

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
      // 使用抽象的夾逼二分求
      long long left = INT_MIN;    // 看來以後要特別注意類型了,全部改成long long
      long long right = 0;
      for (long long num : nums) {
        left = max(num, left);
        right += num;
      }
      while (left < right) {
        long long mid = left + (right - left) / 2;
        // 看看最大值爲mid的時候能分成幾對
        int count = GetM(nums, mid);
        // 發現當前的mid只能夠分count的數太小,說明mid偏大了
        if (count <= m) right = mid;
        else left = mid + 1;
      } 
      return left;
    }
  
    int GetM(vector<int> &a, int n) {
    // 貪心法分數組
      int count = 1;
      long long cur = 0;
      for (int num : a) {
        cur += num;
        if (cur > n) {
          ++count;
          cur = num;
        }
      }
      return count;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章