Leetcode 周賽#202 題解
阿新 • • 發佈:2020-08-18
本週的周賽題目質量不是很高,因此只給出最後兩題題解(懶)。
1552 兩球之間的磁力 #二分答案
題目連結
題意
有n
個空籃子,第i
個籃子位置為position[i]
,現希望將m
個球放到這些空籃子,使得任意兩球間最小磁力最大。(其中,磁力簡化為兩點位置之差)
分析
該題是二分答案的裸題,詳細見程式碼
class Solution { public: bool Judge(vector<int>& a, int x, int m){ int cnt = 1,lastpos = a[0]; for (int i = 1; i < (int)a.size(); i++){ if(a[i] - lastpos >= x){ //兩點間距是否大於答案x cnt++; lastpos = a[i]; } if(cnt == m) return true; } return false; } int maxDistance(vector<int>& position, int m) { //該二分演算法,是考慮[1, n+1) sort(position.begin(), position.end()); //記得先排序!!! int lo = 0x3f3f3f3f; int hi = position[position.size() - 1] - position[0] + 1; //確定兩個籃子最大間距,為二分的上界,注意要+1!!! for (int i = 1; i < (int)position.size(); i++){ int delt = position[i] - position[i - 1]; //確定兩個籃子的最小間距,為二分的下界 lo = min(delt, lo); } while(lo < hi){ int mid = (lo + hi) >> 1; if(Judge(position, mid, m)) //估計答案 lo = mid + 1; //答案可以再高一些 else hi = mid; //說明該答案下的間距無法將所有球放完 } return lo-1; } };
1553 吃掉N個橘子的最少天數 #記憶化搜尋
題目連結
題意
給定n(<= 2e9)
個橘子,每一天你只能從以下三種方案中選擇一種:
- 吃掉一個橘子
- 若剩餘橘子數
n
能被2整除,那麼你可以吃掉n/2
個橘子 - 若剩餘橘子數
n
能被3整除,那麼你可以吃掉2*(n/3)
個橘子
現要求吃掉這n
個橘子的最少天數。
分析
容易知道,當n>3時,吃掉n/2
個橘子,剩餘橘子數即為n/2
;吃掉2*(n/3)
個橘子,剩餘橘子樹即為n/3
。
那我們先預處理,將n$\leq$3的情況記錄下來。接下來考慮轉移方程。
起初我考慮有三個轉移方向:n-1
,n/2
,n/3
,並用陣列記憶化。在如此龐大的資料範圍,不但陣列無法承受,而且會分出更多的子問題。
為了應對空間問題,可以考慮用map
來記憶化。
為了應對時間問題,我們分析到,對於當前剩餘橘子數n
,
- 方案二分析:\(n\ Mod\ 3 = 0, 1, 2\),餘數為0,顯然吃掉n/3個橘子即可;餘數為1時,說明我們需要用n/3天的時間將3的倍數個橘子吃完,最後剩下一個橘子,需要1天;同理,餘數為2時,說明我們用n/3天將3的倍數個橘子吃完後,還需要用兩天時間(使用方案一)將剩下2個橘子吃完。
- 方案三如方案二分析同理,我們要用n/2將2的倍數個橘子吃完後,還需要\(n\ Mod\ 2\)天(使用方案一,且已經預處理過)吃掉剩餘的橘子。
因此,我們只需要交給程式去考慮當前的n是選擇方案二更優還是方案三,自頂而下向下遞迴。無需再考慮n-1
class Solution {
private:
unordered_map<int, int> dp;
public:
int minDays(int n) {
if(n == 1) return dp[1] = 1;
else if(n == 2) return dp[2] = 2;
else if(n == 3) return dp[3] = 2;
else if(dp.count(n)) return dp[n];
else return dp[n] = min(minDays(n / 3) + 1 + n % 3,
minDays(n / 2) + 1 + n % 2);
}
};
在筆記本最後幾點電量寫完題解qaq