0
点赞
收藏
分享

微信扫一扫

leetcode:杨辉三角

一叶随风_c94d 2024-11-08 阅读 19

二分查找习题篇(上)

1.二分查找

题目描述:

解法一:暴力解法

解法二:二分查找算法

当数组具有“二段性”时,我们就可以用二分查找算法。

算法思路:

细节问题:

1.循环结束的条件

2.为什么是正确的?

3.时间复杂度

代码实现:

class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        int left=0,right=nums.size()-1;
        while(left<=right)//每次查找的元素都是未知的,所以要取等号
        {
            int mid=left+(right-left)/2;  //防止溢出
            if(nums[mid]>target) right=mid-1;
            else if(nums[mid]<target) left=mid+1;
            else return mid;
        }
        return -1;
    }
};

朴素二分模版:

​ while(left<=right)//每次查找的元素都是未知的,所以要取等号
​ {
​ int mid=left+(right-left)/2; //防止溢出,替换成left+(right-left+1)也可以,只不过是偶数个元素时,mid有2个中间值,左右均可
​ if(……)

​ right=mid-1;
​ else if(……)

​ left=mid+1;
​ else

​ return ……;
​ }

2.在排序数组中查找元素的第一个和最后一个位置

题目描述:

解法一:暴力查找

解法二:二分查找

当数组具有“二段性”时,我们就可以用二分查找算法。接下来我们来寻找该数组的“二段性”.

记左边界为Bleft,右边界为Bright.

1.查找区间的左端点

细节处理:

1.循环条件:

2.求中点的操作:

2.查找区间右端点:

细节处理:

1.循环条件:

2.求中点的操作:

代码实现:
class Solution
{
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        // 处理边界情况
        if(nums.size() == 0) 
            return {-1, -1};

        int begin = 0;
        // 1. 二分左端点
        int left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) 
                left = mid + 1;
            else 
                right = mid;
        }
        
        // 判断是否有结果
        if(nums[left] != target) 
            return {-1, -1};
        else 
            begin = left; // 标记⼀下左端点
        
        // 2. 二分右端点
        left = 0, right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] <= target) 
                left = mid;
            else 
                right = mid - 1;
        }
        
        return {begin, right};
    }
};

查找区间左端点的模版:

while(left < right)
{
int mid = left + (right - left) / 2;
if(……) left = mid + 1;
else right = mid;
}

查找区间右端点的模版:

while(left < right)
{
int mid = left + (right - left + 1) / 2;
if(……) left = mid;
else right = mid - 1;
}

3.搜索插入位置

题目描述:

算法思路:

本题数组是一个排序数组,具有“二段性”时,我们就可以用二分查找算法。

代码实现:

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

4.x 的平方根

题目描述:

解法一:暴力查找

算法思路:

依次枚举 [0, x] 之间的所有数 i :

  • 如果 i * i == x ,直接返回 x ;

  • 如果 i * i > x ,说明之前的⼀个数是结果,返回 i - 1 。

代码实现:
class Solution {
public:
    int mySqrt(int x) {
        // 由于两个较⼤的数相乘可能会超过 int 最⼤范围
        // 因此⽤ long long
        long long i = 0;
        for (i = 0; i <= x; i++)
        {
            // 如果两个数相乘正好等于 x,直接返回 i
            if (i * i == x) return i;
            // 如果第⼀次出现两个数相乘⼤于 x,说明结果是前⼀个数
            if (i * i > x) return i - 1;
        }
        // 为了处理oj题需要控制所有路径都有返回值
        return -1;
    }
};

解法二:二分查找

本题数组具有“二段性”时,我们就可以用二分查找算法。

算法思路:
代码实现:
class Solution
{
public:
    int mySqrt(int x) 
    {
        if(x < 1) return 0; // 处理边界情况
        int left = 1, right = x;
        while(left < right)
        {
            long long mid = left + (right - left + 1) / 2; // 防溢出
            if(mid * mid <= x) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

最后,本篇文章到此结束,感觉不错的友友们可以一键三连支持一下笔者,有任何问题欢迎在评论区留言哦~

举报

相关推荐

0 条评论