【每日算法Day 102】美團 AI 平臺算法工程師面試編程題

今天去嘗試了一下美團 AI 平臺,兩次面試連一起。但是兩位面試官小哥都是做推薦的,我們互相都不瞭解對方怎麼做的。於是乎就做算法題,講論文(把不懂的人講懂確實困難),然後全程小哥給我介紹他們部門情況,我就掛機聽着。不管這家拿不拿得到,就當刷刷經驗吧,也挺不錯的。一共三道題目,前兩道一個最長上升子序列,一道快速排序,就不講了,都是原題。

題目描述

題目鏈接:
牛客網:分石子[1]

牛牛有 n 堆石子堆,第 i 堆一共有 a[i] 個石子。

牛牛可以對任意一堆石子數量大於 1 的石子堆進行分裂操作,分裂成兩堆新的石子數量都大於等於 1 的石子堆。

現在牛牛需要通過分裂得到 m 堆石子,他想知道這 m 堆石子的最小值最大可以是多少?

示例:

        輸入:
3,5,[3,5,6]
輸出:
2
解釋:
把5分裂成2和3
把6分裂成2和4
得到五堆石子[3,2,3,2,4]
      

備註:

  • 1 \le n \le 10^5, n \le m \le \sum{a_i}, 1 \le a_i \le 10^9
  • 第一個參數 n 代表石子堆的個數
  • 第二個參數 m 表示需要得到的石子堆數。
  • 第三個參數 vector a 代表每堆石子堆的石子個數

題解

一拿到這個題目,就看出來這是一道二分答案的題目。

首先定義上下界 l = 1, r = min{a[i]} ,也就是說,每一堆個數最小值至少爲 1 ,最多就是初始的時候最小的那堆個數。

然後對於 mid = (l + r) / 2 ,含義就是假設最終最小的那堆有 mid 個。我們求出初始時每一堆最多可以劃分出多少個數全部大於等於 mid 的子堆,顯然個數是 a[i] / mid 取整,記總堆數爲 cnt

如果 cnt < m ,那麼說明 mid 太大了,你最多也不可能劃分成 m 堆,所以更新 r = mid - 1 。如果 cnt > m ,那麼說明 mid 太小了,你能劃分的堆數大於了 m ,那麼更新 l = mid + 1 。最後如果 cnt = m ,你就暫存一下答案,因爲這時的 mid 是有可能成爲最終答案的。但是 mid 還是可能太小了,因爲 mid 稍微大一點 cnt 是不會變的,所以繼續更新 l = mid + 1

最終返回暫存的答案 res 即可。注意這題的二分框架和之前做過的有所不同,在等號判斷上得特別小心,我一開始沒想清楚,錯了好多次才通過的。

代碼

        class Solution {
public:
    /**
     * 分石子
     * @param n int整型 
     * @param m long長整型 
     * @param a int整型vector 
     * @return int整型
     */
    int solve(int n, long long m, vector<int>& a) {
        typedef long long ll;
        ll l = 1, r = *min_element(a.begin(), a.end()), res = 0;
        while (l <= r) {
            ll mid = l + (r - l) / 2;
            ll cnt = 0;
            for (auto x : a) {
                cnt += x / mid;
            }
            if (cnt < m) r = mid - 1;
            else {
                l = mid + 1;
                res = mid;
            }
        }
        return res;
    }
};

      

參考資料

[1]

牛客網:分石子: nowcoder.com/questionTe

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