點擊上方「程式設計師大白」,選擇「星標」公眾號
重磅乾貨,第一時間送達
題目分析:給出一串n個數的序列,要求將這n個數分成m個塊,算出每個塊中數的總和,要保證總和的最大值最小。
解題思路:最小化最大值,顯然是二分搜索結果判斷是否可行,關鍵在於判斷函數的設計。判斷函數可以從另一個角度考慮,假設當前枚舉的最大值是limit,那麼肯定每個塊的最大值都不能超過這個限制。那麼從左到右掃一遍,記錄當前的累加和now,如果掃到第i個數nums[i]的時候,now > sum,說明nums[i]需要放到新的塊中,塊的數目c加一。這樣最後在保證所有塊的總合都小於等於最大值的情況下,看c是否小於等於m,若c <= m,說明還可以繼續二分更小的結果,否則就要二分更大的結果。
算法正確性:舉例說明:數組序列為[1,3,2,1,5],要求分成3塊,初始化二分範圍是[5,12],f(x)為總和最大值不超過x的情況下最少分成幾塊。step 1:l = 5, r = 12, mid = 8, 則f(8) = 2 <= 3.step 2: l = 5, r = 8, mid = 6, 則f(6) = 2 <= 3.step 3: l = 5, r = 6, mid = 5, 則f(5) = 4 > 3.step 4:l = 6, r = 6, l == r, 所以最終結果就是6.每次二分都需要一遍遍歷,這樣算法的複雜度就是O(n * logx),其中x是數的大小,n是數組長度。
CPP代碼
class Solution {
public:
using ll = long long;
bool canSplit(vector<int>& nums, int m, ll limit) {
ll now = 0;
int c = 1, cnt = nums.size();
for (int i = 0; i < cnt; i++) {
now += nums[i];
if (now > limit) {
now = nums[i];
++c;
}
}
return c <= m;
}
int splitArray(vector<int>& nums, int m) {
ll l = 0, r = 0;
int cnt = nums.size();
for (int i = 0; i < cnt; i++) {
l = max(l, (ll)nums[i]);
r += nums[i];
}
while (l < r) {
ll mid = (l + r) >> 1LL;
if (canSplit(nums, m, mid)) r = mid;
else l = mid + 1;
}
return r;
}
};重磅!程式設計師大白交流群-學術微信交流群已成立
額外贈送福利資源!邱錫鵬深度學習與神經網絡,pytorch官方中文教程,利用Python進行數據分析,機器學習學習筆記,pandas官方文檔中文版,effective java(中文版)等20項福利資源
獲取方式:進入群後點開群公告即可領取下載連結
注意:請大家添加時修改備註為 [學校/公司 + 姓名 + 方向]
例如 —— 哈工大+張三+對話系統。
號主,微商請自覺繞道。謝謝!
推薦閱讀
浙大一教授被指多次性騷擾女博士致其跳樓,校方:缺乏證據
這五款冷門但有趣的Chrome插件,能讓你的瀏覽器好用十倍
955 不加班的公司名單:955.WLB
「拍一拍」 能撤回了 !!!
5款Chrome插件,第1款絕對良心!
關於程式設計師大白
程式設計師大白是一群哈工大,東北大學,西湖大學和上海交通大學的碩士博士運營維護的號,大家樂於分享高質量文章,喜歡總結知識,歡迎關注[程式設計師大白],大家一起學習進步!