leetcode1552題解【二分+貪心】

Z發表於2020-09-23

leetcode1552.兩球之間的磁力

題目連結

演算法

二分+貪心

時間複雜度O(nlogn + nlogm)

1.根據題意描述,我們需要將m個球放入到n個籃子中,根據題目中資料範圍描述發現m <= n,故可以將一個球放入到一個籃子中。這道題主要就是要求出相鄰的兩個球之間的距離的最小值,而且要儘可能的讓這個最小值最大化

2.分析完了題意,下面來分析一下如何解題。剛開始的思路是首先排序,然後將第一個球放到陣列的第一個位置,然後根據剩餘的球的個數列舉球的位置。但因為還需要記錄相鄰兩個球的距離差,如果這樣純暴力的話寫起來太過於繁瑣,並且耗時大,最終該思路未果。在搜尋了大佬們的解題思路後,瞭解到可以使用二分思想來對磁力進行二分,具體思路如下。

3.對於一些球,它們之間磁力的最大值是poisiton陣列中元素的最大值減去最小值(這裡先不考慮球的個數),那麼我們就可以確定了磁力的區間範圍[l,r],然後將[l,r]劃分為[l,mid-1][mid,r],為什麼要這樣劃分呢,因為題目中說了要最大化最小磁力,所以我們要儘可能的使得mid更大。劃分條件就是判斷position陣列是否能夠找到m個籃子使得它能夠滿足相鄰的兩個球之間的距離大於等於mid,如果滿足,則l=mid,否則r=mid-1

4.為了使得最小磁力最大化,我們可以使其中一個球位於最左邊的那個籃子裡,然後再以此列舉球的位置,使得相鄰的兩個球的距離大於等於mid。

5.由此,這道題的總體思路是:先排序,然後二分。

C++程式碼

class Solution {
public:
    int maxDistance(vector<int>& position, int m) {
        sort(position.begin(), position.end());
        int len = position.size();
        int l = 1, r = position[len - 1] - position[0];
        while(l < r){
            int mid = l + r + 1>> 1;
            if(check(mid, position, m))
                l = mid;
            else
                r = mid - 1;
        }
        return l;
    }
    bool check(int k, vector<int>& position, int m){
        int len = position.size();
        int last = position[0];         //last用於記錄上一個存放球的籃子的位置
        int t = 1;             //記錄已經放入到籃子的球的個數
        for(int i = 1; i < len; i++){
            if(position[i] - last >= k){
                ++t;
                last = position[i];
                if(t == m) return true;
            }
        }
        return false;
    }
};

這道題使用的二分模板來源於yxc大佬的二分查詢演算法模板

相關文章