Leetcode算法入门第一天(二分查找)

Leetcode算法入门第一天(二分查找)

  • 704. 二分查找
    • 题目描述
    • 样例
    • 思路
    • 参考代码
  • 278. 第一个错误的版本
    • 题目描述
    • 样例
    • 思路
    • 参考代码
  • 35. 搜索插入位置
    • 题目描述
    • 样例
    • 思路
    • 参考代码

704. 二分查找

题目描述

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

样例

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

思路

数组本来就是有序的,适合使用二分查找算法,二分查找比较容易理解,查找范围为【left,right】,初始查找整个数组,每次取出左右端点的中点值与目标值进行比较,如果相等直接返回中点值下标,如果不等的话,根据大小,移动左端点或者右端点,缩小一半的查找范围,直到左端点超过右端点,循环结束。

参考代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //二分查找:本身就是有序的,进行查找

        //左右端点
        int left=0,right=nums.size()-1;
        //当左端点大于右端点时,循环结束
            //注意重合时,中点值也可能是目标值
        while(left<=right)
        {
            //中点值下标
            int mid=(left+right)/2;
            //如果中点值就是要查找的,直接返回
            if(nums[mid]==target) return mid;
            //如果比较小,左端点向右挪动
            else if(nums[mid]<target) 
            {
                left=mid+1;
            }
            //如果较大,右端点向左挪动
            else 
            {
                right=mid-1;
            }
        }
        //如果循环结束还没返回,说明没找到,返回-1
        return -1;
    }
};

278. 第一个错误的版本

题目描述

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

样例

输入:n = 5, bad = 4
输出:4
解释:
调用 isBadVersion(3) -> false 
调用 isBadVersion(5) -> true 
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。

输入:n = 1, bad = 1
输出:1

思路

从第一个出错的版本为分界线,之前的所有版本为正确的,之后的所有版本都出错,那么相当于有序,我们可以利用二分查找,不断缩小范围。这里默认一定有第一个错误版本,所以循环判断中点的版本是否正确,如果是正确的,说明第一个出错版本在区间【mid+1,right】中如果错误,那么在前面的区间【left,mid】中。循环缩小范围,直到最后左右端点重合,循环结束,返回这个重合点,就是要找的第一个出错版本。
:为防止计算时溢出,中点值用mid=left+(right-left)/2

参考代码

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

class Solution {
public:
    int firstBadVersion(int n) {
        int left=1,right=n;
        //判断中点是正确与否
        while(left<right)
        {
            int mid=left+(right-left)/2;//防止计算溢出
            bool m=isBadVersion(mid);
            //如果中点为错误版本,那么第一个错误版本在【left,mid】中
            if(m) 
            {
                right=mid;
            }
            //如果中点为正确版本,那么第一个错误版本在【mid+1,right】中
            else
            {
                left=mid+1;
            }
        }
        //当left==right时,已经缩小范围到一个点,肯定就是他了
        return left;
        

    }
};

35. 搜索插入位置

题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

样例

输入: nums = [1,3,5,6], target = 5
输出: 2

输入: nums = [1,3,5,6], target = 7
输出: 4

思路

这里使用的也是二分查找法,值得注意的是如果查找失败,返回的是要插入的位置,这里当循环到左右端点重合时,即最后一次循环,有三种情况:
1.中间值就是目标值,还是直接返回
2.中间值不是目标值,那么要返回最后目标值要插入的位置:
(1)中间值比目标值小,插入位置就是中间值的下一位(mid+1)
(2)中间值比目标值大,插入位置就是中间值所在位置(mid)
可以看到,返回的插入值刚好是更新后的left的值,所以查找失败,直接返回left即可。

参考代码

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) return mid;
            else if(nums[mid]<target) 
            {
                left=mid+1;
            }
            else
            {
                right=mid-1;
            }
        }
        //查找不成功,直接返回left。
        return left;
    }
};

你可能感兴趣的:(Leetcode之算法,leetcode,算法,c++,二分查找)