首页 > 其他分享 >大厂面试高频题——二分查找

大厂面试高频题——二分查找

时间:2024-07-08 17:30:58浏览次数:8  
标签:二分 right target nums int mid 查找 大厂 left

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

思考

二分模板题

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

BM21 旋转数组的最小数字(有重复数字)

思考

剑指offer上原题。数组划分为2个区间,二分搜索逐渐逼近最小值。遇到无法判断区间时,需要顺序逐个查找。

class Solution:
    def minNumberInRotateArray(self , nums: List[int]) -> int:
        # write code here
        left = 0
        right = len(nums)-1
        mid = 0
        while nums[left]>=nums[right]:
            if right-left == 1:
                return nums[right]
            mid = int((left+right)/2)
            if nums[left] == nums[right] and nums[left] == nums[mid]:
                res = nums[left]
                for i in range(left+1,right+1):
                    if nums[i] < res:
                        res = nums[i]
                return res
            if nums[mid] >= nums[left]:
                left = mid
            elif nums[mid] <= nums[right]:
                right = mid
        return nums[left]
  1. 搜索旋转排序数组 (无重复数字搜索指定target)
    整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

思考

根据mid值判断是左有序 还是 右有序。在有序的区间内进行二分查找。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)-1
        #[left,right]
        mid = -1
        while left<=right:
            mid = int((left+right)/2)
            if nums[mid] == target:
                return mid
            if nums[mid] >= nums[left]:
                #左有序
                if target >= nums[left] and target < nums[mid]:
                    # 二分
                    right = mid - 1
                else:
                    left = mid + 1
            else:
                #右有序
                if target > nums[mid] and t arget <= nums[right]:
                    left = mid + 1
                else:
                    right = mid -1
        return -1

153.寻找旋转排序数组中的最小值(无重复)

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

思考

比有重复的要简单一点。两种方法。
方法1:剑指offer版本,比较容易理解:划分为2个区间,逐渐逼近结果。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        left = 0
        right = len(nums)-1
        mid = 0
        while nums[left] > nums[right]:
            if right - left == 1:
                return nums[right]
            mid = (left+right)//2
            if nums[mid] >= nums[left]:
                left = mid
            elif nums[mid] <=nums[right]:
                right = mid
        return nums[0]

方法2:leetcode官方题解。
在二分查找的每一步中,左边界为 low,右边界为 high,区间的中点为 pivot,最小值就在该区间内。我们将中轴元素 nums[pivot] 与右边界元素 nums[high] 进行比较,可能会有以下的三种情况:


class Solution:
    def findMin(self, nums: List[int]) -> int:
        left = 0
        right = len(nums)-1
        mid = 0
        while left < right:
            mid = (left+right)//2
            if nums[mid] < nums[-1]:
                right = mid
            else:
                left = mid + 1
        return nums[left]

34. 在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

思考

划分为2个区间 <target 和 >=target 来寻找左边界。
右边界通过寻找targe+1的左边界-1来代替。优雅

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def getRightBorder(nums, target):
            left = 0 
            right = len(nums)-1
            #right_border = -2
            while left<=right:
                mid = int((left+right)/2)
                if nums[mid] > target:
                    right = mid - 1
                else:
                    left = mid + 1
            return right
        
        def getLeftBorder(nums, target):
            left = 0 
            right = len(nums)-1
            #left_border = -2
            while left<=right:
                mid = int((left+right)/2)
                if nums[mid] < target:
                    left = mid + 1
                else:
                    right = mid - 1
                    #left_border = right
            return left
        
        left_border = getLeftBorder(nums, target)
        #right_border = getRightBorder(nums,target)
        right_border = getLeftBorder(nums, target+1) - 1
        if left_border == len(nums) or nums[left_border] != target:
            return [-1,-1]
        else:
            return [left_border,right_border]

标签:二分,right,target,nums,int,mid,查找,大厂,left
From: https://www.cnblogs.com/forrestr/p/18290406

相关文章

  • 二分
    二分\(\sf\small\color{gray}Binary\)思想要想区分不同,又想种类最少,“二”这个数值可谓是不二人选。原因很简单。因为1+1=2。那你是不是就可以取一个中间值,把一串数据分成两部分,然后依据这个中间值判断目标值是在左边还是右边?二分查找就出来了。二分查找就是在一个\(\s......
  • std::vector 中查找某个元素是否存在
    std::vector中不存在直接查找某个元素是否存在的方法,一般是通过<algorithm>中的std::find,std::find_if,std::count,std::count_if等方法的返回值来判断对应元素是否存在。如当vector中存储的元素为double类型时,需要设定其精度,判断代码如下#include<vector>#include......
  • 查找相差最小的数字
    constfindClosestNumbers=(arr=[1,2,3,4,5,6,7,8,9],target=3)=>{letleft=0;letright=arr.length-1;letminDiff=Infinity;letclosestNumbers=[];while(left<=right){constmid=Math.floor((left+right)/......
  • 【寻迹】二分与三分
    二分与三分二分是一种常用且非常精妙的算法。(英才计划甚至还水了一篇文章)三分法则可以用来解决单峰函数的极值以及相关问题一、二分二分法,在一个单调有序的集合或函数中查找一个解,每次均分为左右两部分,判断解在哪一个部分后调整上下界。每次二分都会舍弃一半区间,因此效率比较高......
  • unity编辑器拓展,查找项目中预制体引用的组件或者脚本
    `usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingUnityEditor;usingUnityEngine.UI;usingSystem.Reflection;usingSystem;publicclassSearchComponent:EditorWindow{privatestringcomponentName="UnityEngine.......
  • 34. 在排序数组中查找元素的第一个和最后一个位置(中等)
    34.在排序数组中查找元素的第一个和最后一个位置1.题目描述2.详细题解(1)朴素二分查找算法(2)改进二分查找算法3.代码实现3.1Python  方法一:  方法二:  方法三:优化方法二3.2Java1.题目描述题目中转:34.在排序数组中查找元素的第一个和最后一个位置2.详......
  • 树状数组实现 查找逆序对
     题意:输入一个整数n。接下来输入一行n个整数 。1<=  <=n ,且每个数字只会出现一次题解:按每个数字的大小存入树状数组#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstintN=10000;intarr[N];lla[N];intn;llquery(intx){ll......
  • 二分模板及其原理
    直接上代码#include<bits/stdc++.h>usingnamespacestd;//#defineintlonglong//防止越界//#defintdoublelongdouble//防止越界constintL=0,R=1e9+1;//整数二分边界//constdoubleL=0,R=1e9+1;//实数二分边界constdoubleEPS=1;......
  • 30个Linux运维面试题,面试一线大厂必备!
    在本文中,我们将讨论30个Linux系统管理员面试问题以及经验丰富的专业人士的答案。(1)为什么需要LVM?LVM(Logicalvolumemanagement)推荐使用LVM管理linux服务器上的磁盘或存储,可以在线调整LVM分区的大小,而不用停止服务器。(2)如何检查内存和CPU统计信息?使......
  • 【34. 在排序数组中查找元素的第一个和最后一个位置】
    题目:给你一个按照非递减顺序排列的整数数组nums,和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1,-1]。你必须设计并实现时间复杂度为O(logn)的算法解决此问题。示例1:输入:nums=[5,7,7,8,8,10],t......