【二分查找】

1. 基本型:

因为我们初始化 right = nums.length - 1 
所以决定了我们的「搜索区间」是 [left, right]

所以决定了 while (left <= right) 
    同时也决定了 left = mid+1 和 right = mid-1 

因为我们只需找到一个 target 的索引即可 

int BinarySearch(int a[],int size,int key)
{
    int left = 0, right = size - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] == key) return mid;
        else if (a[mid] < key) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

2. 左侧边界:

查找第一个与key相等的元素,也就是说等于查找key值的元素有很多,返回这些元素最左边的元素的下标。
(当找到目标时,不会立即返回,而是收紧右边界)

//查找第一个与key相等的元素
int BinarySearch(int a[],int size,int key)
{
    int left = 0, right = size - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] >= key) right = mid - 1;
        else left = mid + 1;
    }
    if (left < size&&a[left] == key)
    {
        return left;
    }
    return -1;
}

查找第一个等于或者大于key的元素,查找第一个等于或者大于key的元素,也就是说查找key值的元素有好多个
,返回这些元素最左边元素的下标;如果没有等于key值的元素,则返回大于key的最左边元素的下标。
//查找第一个等于或者大于key的元素
int BinarySearch(int a[],int size,int key)
{
    //如果a[right]<key,则找不到等于或者大于key的值,直接返回-1
    int left = 0, right = size - 1;
    if (a[right] < key) return -1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] >= key) right = mid - 1;
        else left = mid + 1;
    }
    return left;
}

查找第一个大于key的元素。查找第一个大于key的值,也就是说返回大于key的最左边元素的下标。
//查找第一个大于key的元素
int BinarySearch(int a[],int size,int key)
{
    //如果a[right]<=key,则找不到大于key的值,直接返回-1
    int left = 0, right = size - 1;
    if (a[right] <= key) return -1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] > key) right = mid - 1;
        else left = mid + 1;
    }
    return left;
}

3. 右侧边界:

查找最后一个与key相等的元素,也就是等于查找key值的元素有好多个,返回这些元素最右边元素的下标。
(当找到目标时,不会立即返回,而是收紧左边界)

//查找最后一个与key相等的元素
int BinarySearch(int a[],int size,int key)
{
    int left = 0, right = size - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] <= key) left = mid + 1;
        else right = mid - 1;
    }
    if (right >=0 && a[right] == key)
    {
        return right;
    }
    return -1;
}

查找最后一个等于或者小于key的元素。查找最后一个等于或者小于key的元素,也就是说等于查找key值有很多
,返回这些元素最右边的元素的下标;如果没有等于key值的元素,则返回小于key值的最右边元素的下标。
//查找最后一个等于或者小于key的元素
int BinarySearch(int a[],int size,int key)
{
    //如果a[left]>key,则找不到等于或者小于key的值,直接返回-1
    int left = 0, right = size - 1;
    if (a[left]>key) return -1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] > key) right = mid - 1;
        else left = mid + 1;
    }
    return right;
}

查找最后一个小于key的元素。查找最后一个小于key的元素,也就是说返回小于key的最右边的元素下标。
//查找最后一个小于key的元素
int BinarySearch(int a[],int size,int key)
{
    //如果a[left]>=key,则找不到=小于key的值,直接返回-1
    int left = 0, right = size - 1;
    if (a[left]>=key) return -1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (a[mid] >= key) right = mid - 1;
        else left = mid + 1;
    }
    return right;
}

题目

  1. 基本型:540. 有序数组中的单一元素
/*
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例 1:
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:
输入: nums =  [3,3,7,7,10,11,11]
输出: 10
*/
class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left = 0;
        int len = nums.size(); 
        int right = len - 1;
        while(left <= right){
            int mid = left + (right - left)/2;
            int flag = mid % 2;
            if((!flag && mid + 1 < len && nums[mid] == nums[mid+1])
            || (flag && mid - 1 >= 0 && nums[mid] == nums[mid-1]))
                left = mid + 1;
            else  if((!flag && mid - 1 >= 0 && nums[mid] == nums[mid-1])
            || (flag && mid + 1 < len && nums[mid] == nums[mid+1]))
                right = mid - 1;
            else
                return nums[mid];
        }
        return -1;
    }
};
  1. 基本型:153. 寻找旋转排序数组中的最小值
// 写的太恶心了,待优化
class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0;
        int right = nums.size()-1;
        if(right == 0)
            return nums[0];
        while(left <= right){
            int mid = left + (right - left)/2;
            if(mid -1 >= 0 && nums[mid-1] > nums[mid])
                return nums[mid];
            if(nums[mid] >= nums[left] && nums[mid] >= nums[right])
                left = mid + 1;
            else if(nums[mid] <= nums[left] && nums[mid] <= nums[right])
                right = mid - 1;
            else if(nums[mid] <= nums[left] && nums[mid] >= nums[right])
                return nums[right];
            else
                return nums[left];
        }
        return nums[left];
    }
};
  1. 右边界:744. 寻找比目标字母大的最小字母
class Solution {
public:
    char nextGreatestLetter(vector<char>& letters, char target) {
        int left = 0;
        int right = letters.size();
        while(left < right){
            int mid = left + (right - left) / 2; 
            if(letters[mid] > target)
                right = mid;
            else
                left = mid + 1;
        }
        if(left == letters.size())
            return letters[0];
        return letters[left];
    }
};
  1. 左右边界:34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
    int lower_target(vector<int>& nums, int target){ // 左边界
        int left = 0;
        int right = nums.size();
        while(left < right){
            int mid = left + (right - left)/2;
            if(nums[mid] >= target)
                right = mid;
            else 
                left = mid + 1;
        }
        // cout << left << " " << right << endl;
        if(left >= nums.size() || (left >= 0 && nums[left] != target))
            return -1;
        return left;
    }

    int upper_target(vector<int>& nums, int target){ // 右边界
        int left = 0;
        int right = nums.size();
        while(left < right){
            int mid = left + (right - left)/2;
            if(nums[mid] > target)
                right = mid;
            else
                left = mid + 1;
        }
        // cout << left << " " << right << endl;
        if(left-1 >= nums.size() || (left-1 >= 0 && nums[left-1] != target))
            return -1;
        return left - 1;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size() > 0)
            return {lower_target(nums,target), upper_target(nums,target)};
        else
            return {-1,-1};
    }
};
posted @   fwx  阅读(28)  评论(2编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示