二分查找学习入门——【c语言】leetcode配合习题

前言

我一直不知道二分查找有这么多练习和变式,本以为是一个简单深邃的思想用来学习,。但是啊,他的具体应用就没有那么简单了。因此,我配合着leetcode和洛谷的题目和学习资料,努力的刷通关知识点,并且努力的把知识点归纳总结,与君共勉

                                        

知识点简介

目录

前言

知识点简介

leetcode入门题目

题目链接力扣

二分查找

 思路【例子】

代码 

题目链接 力扣

第一个错误版本

思路

代码

题目链接力扣

x的平方根

代码

题目链接力扣

搜索插入位置

 代码

题目链接力扣

搜索旋转排序数组

代码

题目链接力扣

寻找峰值

思路

代码

题目链接力扣

寻找旋转排序数组中的最小值

思路

代码

题目链接力扣

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

思路

代码

题目链接力扣

快速幂算法

思路

代码

题目链接力扣

有效的完全平方数

 思路

代码



leetcode入门题目

【ps一下,leetcode的提交和acm训练题目是不一样的,大家可以自行学习一下,免得看不懂,不过确实不难哦】

题目链接力扣

二分查找

 思路【例子】

代码 

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l,r,mid;
        l=0;
        r=nums.size()-1;        //数组长度减一
        while(l<=r)
        {
            mid=(l+r)/2;
            if(nums[mid]==target)
                return mid;                //找到才返回
            else if(nums[mid]<target)
                l=mid+1;                    
            else
                r=mid-1;
        }
        return -1;
    }
};


题目链接 力扣

第一个错误版本

思路

和前面不一样的是,虽然有序,但是我们要找到第一个出问题的版本,所以把正确的左区间不断压缩。当 l与r相等输出l

代码

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int l=1,r=n,mid;
        while(l<r)
        {
            mid=(r-l)/2+l;
            if(isBadVersion(mid))
                r=mid;
            else
                l=mid+1;
        }
        return r;
    }
};


题目链接力扣

x的平方根

代码

class Solution {
    public :
    int mySqrt(int x) {
         int l,r,mid;
            l=1;r=x;
            if(x==0)
                return 0;
            while(l<=r)
            {
                
                mid=(r-l)/2+l;
                if(mid<=x/mid && (mid+1)>x/(mid+1))
                    return mid;
                else if(mid>x/mid)
                    r=mid-1;
                else if((mid+1)<=x/(mid+1))
                    l=mid+1;
            }
        return -1;
    }
};


题目链接力扣

搜索插入位置

 代码

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


题目链接力扣

搜索旋转排序数组

思路

代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
       int l,r,mid;
        l=0;
        r=nums.size()-1;        //数组末尾
        while(l<=r)
        {
            mid=(r-l)/2+l;                    //中间位置
            if(nums[mid]==target)
                return mid;                    //返回
            else if(nums[l]<=nums[mid])            //mid在左区间
            {
                if(nums[mid]>target && target>=nums[l])    //目标数在左区间
                    r=mid-1;
                else
                    l=mid+1;                                //目标函数在右区间
            }
            else                                            //mid在右区间
            {
                if(target>nums[mid] &&target<=nums[r])
                    l=mid+1;
                else
                    r=mid-1;
            }
        }
        return -1;                            //找不到
    }
};


题目链接力扣

寻找峰值

思路

这个题我自己撞进了一个误区,因为数组第一个和最后一个都很小,题目里说的很清楚,【你可以假设 nums[-1] = nums[n] = -∞】我当时一直假设他可能在后半段一直单调递增。峰值元素是指其值大于左右相邻值的元素——这个表示是至少递增序列间断插入一个小一点的数,所以在后半段一定有峰值。而且只要输出一个返回值就好

所以我想到一句话,当你找不到思路和方法时,为什么不再看一遍题目呢。所以不管怎么说 

代码

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        if(nums.size()<=1){
            return 0;
        }
        for (int i = 0; i < nums.size()-1; i++) {
            if(nums[i]>nums[i+1]){
                return i;
            }
        }
        return nums.size()-1;

    }
};


题目链接力扣

寻找旋转排序数组中的最小值

思路

寻找排序数组的分治寻找,跟前面的螺旋类型很类似

代码

class Solution {
public:
    int findMin(vector<int>& nums) {
           int l,r,mid;
           l=0;r=nums.size()-1;
           while(l<=r)
           {
                mid=(r-l)/2+l;
                if(nums[l]<=nums[r])        //一开始就排序好了,那就返回最左边的
                    return nums[l];
                if(nums[l]<=nums[mid])        //如果左边单增,缩短左区间
                    l=mid+1;
                else
                    r=mid;                    //如果不是左边单增,缩短右区间
           }
           return nums[r];                    //返回
    }
};


题目链接力扣

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

思路

我还是一个c++没学完的菜鸟啊,确实不太理解怎么返回两个数值,但是这个题本质是求找到一个数值第一次和最后一次出现的位置,注意这个是一个升序数组,所以用两个函数分别求出来第一次和最后一次的位置

向下取整不更新右边界会出现死循环,向上取整不更新左边界会出现死循环

代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int n = nums.size();

        vector<int> ans(2, -1);
        if (n == 0) return ans;
        
        // 求第一次出现的位置
        int l = 0, r = n - 1;
        while (l < r) {
            int mid = l + r >> 1;                //向下取整
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;                    //更新左循环
        }
        if (nums[r] != target) return ans;
        ans[0] = r;

        //求最后一次出现的位置
        l = 0, r = n - 1;
        while (l < r) {
            int mid = l + r + 1 >> 1;            //向上取整
            if (nums[mid] <= target) l = mid;
            else r = mid - 1;                    //更新右循环
        }
        ans[1] = r;

        return ans;
    }
};


题目链接力扣

快速幂算法

思路

 快速幂算法哦,只是刚好不用取余

之前写过关于快速幂算法的博客,大家可以自行学习一下,但是我还是认真的复习练习了一遍。这里确实是用到了二分的思想,不断除以2来减小时间复杂度,看我代码吧。快速幂不是很难的算法,但是很重要哦

代码

class Solution {
public:
    double quickMul(double x, long long N)        //原来leetcode可以定义函数
    {
        double sum=1.0;
        while(N)
        {
            if(N%2==1)
                sum*=x;                            //奇数就乘一个
            x*=x;
            N/=2;
        }
        return sum;
    }
    double myPow(double x, int n) {
        long long N=n;
        return N>0?quickMul(x,N):1/quickMul(x,-N);        //负数情况倒数
    }
};


题目链接力扣

有效的完全平方数

 思路

倒也没啥,和前面的算术平方根很类似,我们就是要寻找在比m小的整数中有没有他的平方根,也是用到二分法一个一个来找哦

代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值