首页 > 其他分享 >·跟着代码随想录刷力扣· ·数组部分· 2. 二分法

·跟着代码随想录刷力扣· ·数组部分· 2. 二分法

时间:2024-04-05 13:59:10浏览次数:26  
标签:last target nums int 随想录 pos 二分法 middle 刷力

leetcode题目:704 二分法

一、回顾顺序搜索

(一) 无序列表的顺序搜索,时间复杂度O(n)

    def search(self, nums: List[int], target: int) -> int:
        pos = 0
        while pos < len(nums):
            if nums[pos] == target:
                return pos
            pos = pos + 1
        return -1

(二) 考虑有序列表的顺序搜索,时间复杂度O(n)

注意:与无序列表的顺序搜索相比,这种方法只有在列表中没有target的时候才会提高效率

    def search(self, nums: List[int], target: int) -> int:
        #有序的顺序搜索
        pos = 0
        while pos < len(nums):
            if nums[pos] == target:
                return pos
            elif nums[pos] > target:
                return -1
            pos = pos + 1
        return -1

二、二分法是什么

充分地利用列表有序的特性。

在顺序搜索时,如果一个元素不是目标元素,就剩下n-1个元素需要进行比较。

但二分搜索从列表中间的元素开始进行比较,而不是按顺序搜索列表。如果这个元素就是目标元素,那就立即停止搜索;如果不是则可以利用列表有序的特性,排除一半的元素。如果目标元素比中间的元素大,就可以直接排列表的左半部分和中间的元素。

时间复杂度的计算O(logn)

如表所示,当拆分足够多次后,会得到只含一个元素的列表,这个列表要么是目标元素,要么不是,但搜索过程已经完成。到这一步,需要比较i次,且使得\tfrac{n}{2^{i}}=1,由此可得i=logn

比较次数剩余元素的个数
1\tfrac{n}{2}
2\tfrac{n}{4}
3\tfrac{n}{8}
...
i\tfrac{n}{2^{i}}

三、什么时候使用

 可以使用二分法的前提条件:【==看到这个条件就可以首先思考二分法适用与否】

        1. 有序数组  2. 无重复元素

        如果有重复元素的话,返回的下标可能不对

四、如何使用

    def search(self, nums: List[int], target: int) -> int:
        first = 0
        last = len(nums) - 1

        while first <= last:
            midpoint = (first + last) //2    #注意是整除运算符,得整除midpoint才有意义
            if target ==  nums[midpoint] :
                return midpoint
            elif target < nums[midpoint]:
                last = midpoint-1
            elif target > nums[midpoint]:
                first = midpoint+1
        return -1

五、· 重点辨析 · 边界条件的判断

例如到底是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)

(一) 左闭右闭

何为左闭右闭?其实就是最开始定义last的时候,将last定义为:last = len(nums)-1,这样一来,nums[last]一直可以取到值,因此:

  • while (first <= last) 要使用 <= ,因为first == last是有意义的【存在nums[last]】,所以使用 <=
  • if (nums[midpoint] > target)  last要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

(二) 左闭右开

何为左闭右开?其实就是最开始定义last的时候,将last定义为:last = len(nums),这样一来,最初的nums[last]没有意义

  • while (first < last) ,这里使用 < ,因为first == last在区间[left, right)是没有意义的
  • if (nums[midpoint] > target) last更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

标签:last,target,nums,int,随想录,pos,二分法,middle,刷力
From: https://blog.csdn.net/weixin_51694605/article/details/137345008

相关文章