二分法

英击长空發表於2024-04-01

概述

二分查詢詳解.md

STL C++ 二分查詢庫

二分查詢庫

閉區間、左閉右開區間和開區間

影片講解二分法

class Solution {
    // lower_bound 返回最小的滿足 nums[i] >= target 的 i
    // 如果陣列為空,或者所有數都 < target,則返回 nums.size()
    // 要求 nums 是非遞減的,即 nums[i] <= nums[i + 1]

    // 閉區間寫法
    int lower_bound(vector<int> &nums, int target) {
        int left = 0, right = (int) nums.size() - 1; // 閉區間 [left, right]
        while (left <= right) { // 區間不為空
            // 迴圈不變數:
            // nums[left-1] < target
            // nums[right+1] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid + 1; // 範圍縮小到 [mid+1, right]
            else
                right = mid - 1; // 範圍縮小到 [left, mid-1]
        }
        return left; // 或者 right+1
    }

    // 左閉右開區間寫法
    int lower_bound2(vector<int> &nums, int target) {
        int left = 0, right = nums.size(); // 左閉右開區間 [left, right)
        while (left < right) { // 區間不為空
            // 迴圈不變數:
            // nums[left-1] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid + 1; // 範圍縮小到 [mid+1, right)
            else
                right = mid; // 範圍縮小到 [left, mid)
        }
        return left; // 或者 right
    }

    // 開區間寫法
    int lower_bound3(vector<int> &nums, int target) {
        int left = -1, right = nums.size(); // 開區間 (left, right)
        while (left + 1 < right) { // 區間不為空
            // 迴圈不變數:
            // nums[left] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid; // 範圍縮小到 (mid, right)
            else
                right = mid; // 範圍縮小到 (left, mid)
        }
        return right; // 或者 left+1
    }

public:
    vector<int> searchRange(vector<int> &nums, int target) {
        int start = lower_bound(nums, target); // 使用其中一種寫法即可
        if (start == nums.size() || nums[start] != target)
            return {-1, -1};
        // 如果 start 存在,那麼 end 必定存在
        int end = lower_bound(nums, target + 1) - 1;
        return {start, end};
    }
};

作者:靈茶山艾府
連結:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/1980196/er-fen-cha-zhao-zong-shi-xie-bu-dui-yi-g-t9l9/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

題目

34. 在排序陣列中查詢元素的第一個和最後一個位置

二分法寫作技巧:

1、首先 while (left <= right) 怎麼寫取決於,left right 是閉區間還是開區間。
2、mid = (left + right) / 2; 這個是不影響的,所有區間都這麼寫
3、將三種方法寫全,不要偷懶 。一開始我的 == 情況沒有分開寫導致了一大堆的問題

使用 STL 庫

    vector<int> searchRange(vector<int> &nums, int target) {
        auto bound =  equal_range(nums.begin(), nums.end(), target);
        int left = bound.first - nums.begin();
        int right = bound.second - nums.begin();
        return {left, right};
    }

我的解題思路

我的思路:
1、尋找第一個小於。當等於的時候,繼續往左移。而不是 直接退出。知道找到最左一個滿足條件的值
2、尋找第一個大於,跟1一樣。

我的程式碼


#include "vector"
#include "set"
#include "iostream"
#include "algorithm"
#include "tuple"
#include "unordered_map"

using namespace std;

class Solution {
public:
    // 找到左邊第一個
    int find_first(vector<int> &nums, int target) {
        int result = -1;
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        while (left <= right) { // 在閉區間之中尋找 [left, right]
            mid = (left + right) / 2;
            if (nums[mid] == target){
                result = mid;
                right = mid -1 ; // 當找到一個時,繼續往左邊尋找
            }else if (nums[mid] > target) {
                right = mid -1 ;
            } else if (nums[mid] < target) {
                left = mid + 1;
            }
        }
        return result;

    }

    //    找到右邊最後一個
    int find_last(vector<int> &nums, int target) {
        int result = -1;
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] == target){
                result = mid;
                left = mid + 1;
            }else if (nums[mid] > target) {
                right = mid -1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            }
        }
        return result;
    }

    vector<int> searchRange(vector<int> &nums, int target) {
        int left = find_first(nums, target);
        int right = find_last(nums, target);
        if (nums.size() == 0 || left > right) {
            return {-1, -1};
        }
        return {left, right};
    }
};

int main() {
    std::cout << "Hello, World!" << std::endl;
    Solution *a = new Solution();
    vector<int> nums = {5, 7, 7, 8, 8, 10};
    a->searchRange(nums, 8);
    return 0;
}


704. Binary Search 704. 二分查詢 🟢

我的解題思路和程式碼

1、一個簡單的二分查詢

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] == target){
                return mid;
            }else if (nums[mid] > target) {
                right = mid -1 ;
            } else if (nums[mid] < target) {
                left = mid + 1;
            }
        }
        return -1;
    }
};

使用STL庫

#include "algorithm"
int searchRange(vector<int> &nums, int target) {
    auto it = lower_bound(nums.begin(), nums.begin() + nums.size()-1, target);
    int left = it - nums.begin();
    return left;
}

劍指 Offer 53 - I. 在排序陣列中查詢數字 I

我的解題思路和程式碼:

1、用二分法找到第一個滿足條件的值
2、然後用一次遍歷找到所有的值

class Solution {
public:
    // 找到左邊第一個
    int find_first(vector<int> &nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        int result = -1;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] == target){
                result = mid;
                right = mid-1;
            }else if (nums[mid] > target) {
                right = mid -1 ;
            } else if (nums[mid] < target) {
                left = mid + 1;
            }
        }
        return result;
    }


    int search(vector<int>& nums, int target) {
        int result = 0;
        int left = find_first(nums, target);
        if(left==-1){
            return 0;
        }
        while (left<nums.size() && nums[left]==target){
            left++;
            result += 1;
        }
        return result;
    }
};

官網題解

1、找到左右兩邊的值,然後取差值

相關文章