Day1-二分查找算法

目录

题目一、二分查找

题目二、第一个错误版本

题目三、搜索插入位置


第一次用LeetCode刷题,属实有点懵。在VS上写好了直接搬过去运行是不行的。

LeetCode它不需要写main函数,也不需要我们判断什么输入输出。

它是直接将题目封装成一个类或者一个函数,测试代码时直接调用的。

咱就是说高级!

好了咱说题目

题目一、二分查找

虽然看起来很简单,但是还是有一些坑的。

无脑刷题的我上去直接就是一顿暴力算法,遍历数组。

然后就是让我震惊的通过率

暴力有风险啊

论看题的重要性,以及可以得出二分查找的效率是真的会提高!O(logN)不是吹牛

int search(int* nums, int numsSize, int target){
    int left=0;
    int right=numsSize-1;
    int mid = (numsSize-1)/2;
    while(left<=right){
        if(nums[mid]==target){
            return mid;
        }
        if(nums[mid]<target){
            left=mid+1;
        }else{
            right=mid-1;
        }
        mid = (left+right)/2;
    }
    return -1;
}

这里需要注意的是,mid的大小,不能是mid=numsSize不然你会得到:

 因为数组会越界呜呜呜

题目二、第一个错误版本

首先就是一个大写的没看懂题

输入n是告诉我们总共有几个版本,根据常识版本号是连续的且是递增的。

bool isBadVersion(version) 这是一个判断是否是坏的版本的函数。

如果该版本是坏的,则返回true!!!!

 接下来就是踩坑记录了:

数组越界!

如果使用mid = (begin+end)/2 的话很可能会溢出,这是因为,如果begin和end都很大那相加当然更大咯

解决办法:int mid = low + (high - low) / 2;

注意最好不要 mid = left/2 + right/2

原因下个题再说呜呜呜,反正很痛苦就对了!

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

class Solution {
public:
    int firstBadVersion(int n) {
        int begin=0;
        int end=n;
        int mid=(begin+end)/2;
        while(begin<=end){
            bool isbadbefore=isBadVersion(mid-1);
            bool isbadnow=isBadVersion(mid);
            bool isbadbehind=isBadVersion(mid+1);
            if(isbadbefore==false && isbadnow==true){
                return mid;
            }
            if(isbadnow==false && isbadbehind==true){
                return mid+1;
            }
            if(isbadnow==false){
                begin=mid+1;
            }else{
                end=mid-1;
            }
            mid=begin/2 + end/2;
        }
        return n+1;
    }
};

这是我写的代码,就是在二分查找的基础上多加了一个判断。

根据第一个坏版本的位置特点,就是第一个坏版本的前一个一定是好的。

But!!我也参考了其他大佬的代码,发现新大陆!

就是说可以只对一边进行判断,如果中间位置是好版本那第一个坏版本一定在右边,如果中间位置是坏版本,那第一个坏版本一定在左边。

当循环结束时,也就是left>right的时候,坏版本一定在left位置!

刚刚发现的一个规律!

就是如果按照mid = (left+right)/2 的方法计算mid,那mid一定不会落在right的位置,除非left和right指向同一个位置!!

这是因为整数的除法是直接舍弃小数点的,所以不可能有

 所以结束循环的时候,left一定指向第一个坏版本!

bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
       int left = 0;
       int right = n-1;
       int mid = right/2;
       while(left<=right){
           if(isBadVersion(mid)==false){
               left=mid+1;
           }else{
               right=mid-1;
           }
           mid = left + (right-left)/2;
       }
       return left;
    }
};

题目三、搜索插入位置

 1、在变化mid的时候,因为会遇到第二题的溢出问题所以,我自以为机智的改成了

mid = left/2 + right/2; 然后就成功的死循环了。真开心!

这是因为int的除法本来就是向下取整的,两个向下取整就相当于在中间位置偏移了2个元素所以就死循环了(其实我也不是很懂)

还是举例子把!

就是如果left在3,right在3,则按照mid = left/2 + right/2来算,mid=3/2+3/2=2;

然后left=mid+1=2+1=3;然后就成功出不了循环了!

所以需要用mid = left + (left + right)/2;

2、就是数组越界的问题!

那就是一个屡教不改啊!朋友

给right赋初值的时候,right = nums.size()-1;

答应我以后不要忘记了减一好吗!

3、就是最后出循环的问题;

就是记住好吧,因为能用二分查找的数组都是已经排好序的。

所以!如果是升序排列的话,那么未找到元素出循环的时候left一定指向查找元素应该插入的位置!

想不清楚的话,自己推一下就好了啊!动脑不如动笔!

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

综上!今天又是开心的一天呢!

再见!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值