德魯週記02 --Leetcode二分查詢題目型別總結

安德魯JANKENPAN發表於2020-10-11

二分查詢

上週因為國慶放假,家人來學校看我所以沒有太多時間學習,就把在leetcode上刷到的二分查詢的三到型別題和大家分享一下。
二分查詢也稱折半查詢(Binary Search),它是一種效率較高的查詢方法。
演算法查詢過程很簡單,相信大家都玩過猜數的遊戲,玩家說猜一個數,遊戲會告訴你大了還是小了,根據這個再繼續猜數。原理類似,這裡就不再介紹了。
但計算機中二分查詢必須滿足兩點要求:
1.必須採用順序儲存結構。
2.必須按關鍵字大小有序排列。
該演算法的時間複雜度是O(log2n)次

Leetcode題目

二分查詢的原理很簡單,非常易學,大家如果學過資料結構應該都知道,但是我在Leetcode上碰到包裝之後的題目時最開始還是一臉懵逼,是在看了題解以後才明白和理解,所以又刷了兩道型別題來加深印象和抓住這種題目特點,今天給大家介紹一下:

1552. 兩球之間的磁力

題目連結: https://leetcode-cn.com/problems/magnetic-force-between-two-balls/.

在這裡插入圖片描述
這道題的其實是一個包裝了之後的陣列問題,可以通過二分查詢去找到最後的答案,而不是要你具體去考慮如何分配。
題意求最大化最小,類似這樣的求最大化最小值、最小化最大值等都可以用二分查詢解決。
通過二分查詢check函式來確定是否滿足查詢標準。題目的難度也就出現在check函式上,二分查詢本身其實並不具備任何難度,大家可以看看後面兩道型別題,在二分查詢部分都是類似的,Check函式上就是區分難度的地方,所以僅僅三道題只是給大家展示一個二分查詢的模型和題目難度的區分點,真正的難題應該不限於此,當然太難的題價效比也有待商榷,希望大家可以通過下面程式碼能夠有所收穫,後面就不一一講解了,實在不懂可以通過連結去看題解,題解講得非常清楚或者留言討論。
程式碼

class Solution {
public:
    bool check(int x, vector<int>& position, int m) {
        int pre = position[0], cnt = 1;
        for (int i = 1; i < position.size(); ++i) {
            if (position[i] - pre >= x) {
                pre = position[i];
                cnt += 1;
            }
        }
        return cnt >= m;
    }
    int maxDistance(vector<int>& position, int m) {
        sort(position.begin(), position.end());
        int left = 1, right = position.back() - position[0], ans = -1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (check(mid, position, m)) {
                ans = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return ans;
    }
};


LCP 12. 小張刷題計劃

題目連結: https://leetcode-cn.com/problems/xiao-zhang-shua-ti-ji-hua/.

在這裡插入圖片描述

class Solution {
public:
    bool Check(int limit, vector<int> cost, int day) {
      // 每組劃分 limit 的最大和,貪心劃分看有多少組
        int useday, totaltime, maxtime;
        useday = 1; totaltime = maxtime = 0;
        for (int i=0; i<cost.size(); ++i) {
            int nexttime = min(maxtime, cost[i]);
            if (nexttime + totaltime <= limit) {
                totaltime += nexttime;
                maxtime = max(maxtime, cost[i]);
            } else {
                ++useday;
                totaltime = 0;
                maxtime = cost[i];
            }
        }
        return (useday <= day);
    }
    int minTime(vector<int>& time, int m) {
        int left, right, middle;
        left = right = 0;
        for (int i=0; i<time.size(); ++i) {
            right += time[i];
        }
        while (left <= right) {
            middle = (left + right) >> 1;
            if (Check(middle, time, m)) right = middle - 1;
            else left = middle + 1;
        }
        return left;
    }
};


410. 分割陣列的最大值

題目連結: https://leetcode-cn.com/problems/split-array-largest-sum/.
在這裡插入圖片描述

class Solution {
public:
    bool check(vector<int>& nums, int x, int m) {
        long long sum = 0;
        int cnt = 1;
        for (int i = 0; i < nums.size(); i++) {
            if (sum + nums[i] > x) {
                cnt++;
                sum = nums[i];
            } else {
                sum += nums[i];
            }
        }
        return cnt <= m;
    }

    int splitArray(vector<int>& nums, int m) {
        long long left = 0, right = 0;
        for (int i = 0; i < nums.size(); i++) {
            right += nums[i];
            if (left < nums[i]) {
                left = nums[i];
            }
        }
        while (left < right) {
            long long mid = (left + right) >> 1;
            if (check(nums, mid, m)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
};


下週一定要把資料庫的思維導圖做出來,已經拖了兩週了,希望這個flag別再倒了。

相關文章