Leetcode之二分查找系列

二分查找

704. 二分查找

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

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

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
核心思想:在二分查找的基础上需要进一步判断插入的位置,即在二分查找没找到的情况下,left和right指针的位置

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

注意:如果target没有数组中,那么left和right最终会指向同一个位置,且这个位置是小于target的位置,所以最后返回的结果是right+1
笔记:二分查找返回的mid对应的元素一定是小于等于target的!!!

解法二:

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

本地属于大于等于x的最小下标问题
注意:当寻求的mid的对应元素小于等于target时,res放在大于等于判断的下面

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

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
核心思想:在二分查找的基础上需要进一步判断target在数组中的范围,没找到返回[-1, -1],找到了就在寻找target的范围

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

注意:最后两个while的判断,一定要把范围的判断放在前面,不然会报错

69. x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
核心思想:在二分查找的基础上,在找不到的情况下,需要判断mid的位置

class Solution:
    def mySqrt(self, x: int) -> int:
        left, right = 0, x
        while left <= right:
            mid = (left + right) // 2
            val = mid * mid
            if val == x: return mid
            elif val > x: right = mid - 1
            else: left = mid + 1
        if mid * mid > x: return mid - 1
        else: return mid

注意:最后返回的时候,需要判断mid的大小,如果mid的平方大于了x,则mid需要-1,否则直接返回mid

解法二:

class Solution:
    def mySqrt(self, x: int) -> int:
        left, right = 0, x
        res = 0
        while left <= right:
            mid = (left + right) // 2
            val = mid * mid
            if val <= x:
                res = mid
                left = mid + 1
            else:
                right = mid - 1
        return res

本题属于小于等于x的最大下标问题
注意:当寻求的mid的对应元素(mid*mid)小于等于target(n)时,res放在小于等于判断的下面

367. 有效的完全平方数

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
核心思想:类似于求平方根,唯一不同的是找不到返回False

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left, right = 0, num
        while left <= right:
            mid = (left + right) // 2
            square = mid * mid
            if square == num: return True
            elif square > num: right = mid - 1
            else: left = mid + 1
        return False

441. 排列硬币

你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。
给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。
核心思想:利用二分查找找到那个mid,使得其等差和为n

class Solution:
    def arrangeCoins(self, n: int) -> int:
        left, right = 0, n
        while left <= right:
            mid = (left +right) // 2
            sums = mid * (mid + 1) /2
            if sums == n: return mid
            elif sums > n: right = mid - 1
            else: left = mid + 1
        return right

解法二:

class Solution:
    def arrangeCoins(self, n: int) -> int:
        left, right = 0, n
        res = 0
        while left <= right:
            mid = (left + right) // 2
            if mid * (mid + 1) / 2 <= n:
                res = mid
                left = mid + 1
            else:
                right = mid - 1
        return res

同x的平方根一样,本题属于小于等于x的最大下标问题

猜你喜欢

转载自blog.csdn.net/qq_33757398/article/details/126804541