每日leetcode——二分查找

逻辑玄铁探
• 阅读 1063

题目

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

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

暴力枚举

for循环遍历数组元素,挨个判断。时间复杂度O(n)

def search(nums, target) -> int:
    for i,num in enumerate(nums):
        if num == target: return i
    return -1

二分法

二分法,适用于这种有序数组的查找。
二分法的思想,就是每次取中间的值与target比较,然后缩小范围再取中间的值...:

  • 如果中间值<target,就收缩left
  • 如果中间值>target,就收缩right
  • 如果中间值=target,需要分情况讨论

    • 如果数组是[1,2,3,4]这种有序且不重复,就直接找到了
    • 如果数组是其他情况,比如有重复,部分有序,部分有序且有重复,就需要考虑左右边界,因为数组中可能有多个等于target的数,需要找最左侧的或是最右侧的

二分法时间复杂度O(logn),n/2^k=1,k=logn

标准二分,数组有序无重复元素

[1,2,3,4,5],数组有序且无重复元素
while循环实现

def search(nums, target) -> int:
    left,right = 0, len(nums)-1
    while left <= right:
        mid = (left+right)//2
        if nums[mid]==target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1

递归实现

def search(nums,target) -> int:
    def searchInternally(nums,target,left,right):
        if left<=right:
            mid = (left+right)//2
            if nums[mid]==target: 
                return mid
            elif nums[mid]<target:
                return searchInternally(nums,target,mid+1,right)
            else:
                return searchInternally(nums,target,left,mid-1)
        else:
            return -1
    return searchInternally(nums,target,0,len(nums)-1)

考虑边界

数组有重复元素:[1,2,2,2,3]
数组部分有序:[4,5,6,1,2,3]

# 查找左边界
def search(nums,target):
    left,right = 0, len(nums)-1
    while left<right:
        mid = (left+right)//2
        # 因为有重复元素,并且寻找左边界,所以当匹配到target后,收缩right,继续向左查找
        if nums[mid]==target:
            right = mid
        if nums[mid] > target:
            right = mid -1
        if nums[mid] < target:
            left = mid +1
    return left if nums[left]==target else -1

# 查找右边界
def search(nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        # 因为查找右边界,mid原本的计算是向下取整,导致靠左,所以+1靠右
        mid = (left + right) // 2 + 1
        if nums[mid] == target:
            # 收缩left,继续向右查找
            left = mid
        if nums[mid] > target:
            right = mid - 1
        if nums[mid] < target:
            left = mid + 1
    return right if nums[right] == target else -1

数组部分有序,且重复:[1,2,2,3,1,2,2,3]

# 查找左边界
def search(nums, target):
    left,right = 0, len(nums)-1
    while left < right:
        mid = (left+right)//2
        if nums[mid]==target:
            right = mid
        if nums[mid]>target:
            # 因为数组部分有序且重复,mid大于target时,
            # 有可能mid左侧没有目标值,在右侧有,因此收缩right时只能一点一点收缩
            right = right - 1
        if nums[mid]<target:
            left = mid + 1
    return left if nums[left]==target else -1

二分法中间值溢出

(left+right)//2虽然能计算出中间值,但是这种简单的计算方式可能会存在整数溢出的可能。
虽然,在python3中,int不会溢出。
比如,假设当前整数的最大范围是20,如果left=10,right=20,此时left+right已经超过最大范围,就会溢出。
更科学的计算方法是:(right-left)//2+left

点赞
收藏
评论区
推荐文章
好买-葡萄 好买-葡萄
4年前
【数据结构与算法】—— 二分查找
1.二分查找的概念二分查找指的是在排好序的数组中,找到目标元素。如果元素存在则返回元素的下标,不存在则返回1.下面以升序为例进行简单描述2.查找过程:取数组中间元素与查找元素target比较。如果target等于中间元素则直接返回中间元素的下标,如果target小于数组中间元素则在数组左边查找,如果target大于数组中间元素则在右边查找。重复以上步骤。
BichonCode BichonCode
5年前
双指针问题
一、双指针之左右指针相关题目1.1题目要求:给定一个升序排列的整数数组,找到两个数,使它们的和等于给定的数,有且仅有一个满足条件的解,返回索引。题目分析:需要两个指针,一个指向开头,一个指向末尾,然后向中间遍历,如果指向的两个数相加正好等于target的话,直接返回两个指针的位置即可,若小于target,左指针右移一位,若大于target,右
九路 九路
5年前
二分查找法的递归和非递归的实现
//二分查找法非递归实现,在一个有序的数组中查找e元素的位置,找不到返回1publicstaticintbinarySearch(intdata,inte){intl0;intrdata.length1;while(l<r){
Stella981 Stella981
4年前
Leetcode 703. 数据流中的第K大元素
1.题目要求设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。你的KthLargest 类需要一个同时接收整数 k和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用KthLargest.add,返回当前数据流中第K大的元素。示例:
Stella981 Stella981
4年前
LeetCode 5561. 获取生成数组中的最大值
文章目录1\.题目2\.解题1\.题目给你一个整数n。按下述规则生成一个长度为n1的数组nums:nums00nums11当2<2i<n时,nums2inumsi
Stella981 Stella981
4年前
Golang可变参数
Go可变参数语法如果一个函数最后一个参数被标记为…T,表示函数可以接受一个可变的参数。比如,我们想在nums中查找num是否存在:funcfind(numint,nums…int){}目的是通过find函数,在nums中查找num。比如:find(89,89,90
Stella981 Stella981
4年前
LeetCode:283.移动零——简单
题目:283.移动零:给定一个数组nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。示例:输入:0,1,0,3,12输出:1,3,12,0,0说明:1.必须在原数组上操作,不能拷贝额外的数组。2.尽量减少操作
Stella981 Stella981
4年前
Leetcode724:寻找数组的中心索引(java、python3)
寻找数组的中心索引给定一个整数类型的数组nums,请编写一个能够返回数组\\“中心索引”\\的方法。我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和。如果数组不存在中心索引,那么我们应该返回1。如果数组有多个中心索引,那么我们应该返回最靠近左边的那一个。
菜园前端 菜园前端
2年前
什么是顺序搜索?
原文链接:什么是顺序搜索?顺序搜索是一种比较低效的搜索算法,但是实现起来相对简单。主要步骤如下:1.遍历数组2.找到跟目标值相等的元素,就返回它的下标3.遍历结束后,如果没有搜索到目标值,则返回1基础案例时间复杂度:O(n)空间复杂度:O(1)javasc
菜园前端 菜园前端
2年前
什么是二分搜索?
原文链接:什么是二分搜索?二分搜索是一种比较高效的搜索算法,但前提必须是有序数组。主要步骤如下:1.从数组的中间元素开始,如果中间元素正好是目标值,则搜索结束2.如果目标值大于或者小于中间元素,则在大于或者小于中间元素的那一半数组中继续二分搜索基础案例时间
深度学习 深度学习
7个月前
LeetCode 2576题解:双指针法求解最多标记下标(排序+贪心策略)
一、题目解读2576题要求在一个整数中寻找最多可标记的下标对:若nums法”的组合思路:1.排序预处理:对原数组nums进行升序排序,确保相同元素聚集,便于后续配对。2.双划分:将排序后的数组分为左右两半(左指针left0,右指针rightn/2),从