力扣704. 二分查找

题目来源(力扣):

https://leetcode.cn/problems/binary-search/description/

题目描述:

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

基本思路:

最基本的算法之一,考察对二分查找知识的掌握和基础编码能力。
难点主要是边界left、right处理,
参考《代码随想录》中,有2种写法,如下:

代码实现:

写法1 [left,right]

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

写法2 [left,right)

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

更多技巧:

当实际使用不好确认边界时,在更新前用left_old、right_old记录left、right,
从而确认left、right是否真正完成了更新,若未更新则直接退出循环
好处是不用在意左右边界,坏处是需要2个辅助空间,以及更多的判断

class Solution
{
public:
    int search(vector<int> &nums, int target)
    {                                          // 随意写法,不用在意左右边界
        int left = 0, right = nums.size() - 1; //[left,right]
        int left_old = left, right_old = right;
        int mid;
        while (left <= right)
        { // 这里一般直接写<=
            left_old = left;
            right_old = right;
            mid = (left + right) / 2;
            if (nums[mid] > target)
            {
                right = mid; // 不用写mid-1
            }
            else if (nums[mid] < target)
            {
                left = mid; // 不用写mid+1
            }
            else
            {
                return mid;
            }
            if (left_old == left && right_old == right)
            { // 临界条件
                if (nums[left] == target)
                    return left;
                else if (nums[right] == target)
                    return right;
                else
                    break;
            }
        }
        return -1;
    }
};

时间复杂度

以上3种写法(或者说理论上二分查找的时间复杂度)为O(logn)

posted @ 2024-10-09 12:11  HB_Computer  阅读(18)  评论(0)    收藏  举报