二分法

概述

二分查找详解.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、找到左右两边的值,然后取差值

posted @ 2024-04-01 20:06  英击长空  阅读(15)  评论(0编辑  收藏  举报