【数据结构与算法】——二分查找

二分法查找

算法思想

二分查找又称折半查找、 对数搜索 ,是一种在有序数组中查找某一特定元素的搜索算法

  • 假设表中元素是按升序排列

  • 选择数组中的元素,将数组分为前后两个区间

    • 如果要找的元素比中间的元素大,那么要找的元素在后半区间,更新后半区间为查找的区间
    • 如果要找的元素比中间的元素小,那么要找的元素在前半区间,更新前半区间为查找的区间
  • 直到最后找到要找的元素,或者整个数组分完

优缺点

优点:比较次数少,查找速度快,平均性能好

缺点:要求待查表为有序表,且插入删除困难。折半查找方法适用于不经常变动而查找频繁的有序列表。

<\cente>

二分法查找实现

非递归实现

def binary_search(alist, item):
    left = 0
    right = len(alist) - 1
    while left <= right:
        mid = left - (left - right) // 2 # 地板除 取中间的值的索引
        if alist[mid] == item:
            return True
        elif item < alist[mid]:
            right = mid - 1
        else:
            left = mid + 1


    return False
testlist = [2, 2]
print(binary_search(testlist, 2))
print(binary_search(testlist, 13))

递归实现

def binary_search(alist, item):
    if len(alist) == 0:
        return False
    else:
        mid = len(alist)//2
        if alist[mid]==item:
          return True
        else:
          if item<alist[mid]:
            return binary_search(alist[:mid],item)
          else:
            return binary_search(alist[mid+1:],item)

testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binary_search(testlist, 3))
print(binary_search(testlist, 13))

时间复杂度

  • 最优时间复杂度: O ( 1 ) O(1) O(1)
  • 最坏时间复杂度: O ( l o g n ) O(logn) O(logn)

Leetcode

153. 寻找旋转排序数组中的最小值

题目描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

你可以假设数组中不存在重复元素。

示例 1:

输入: [3,4,5,1,2]
输出: 1

示例 2:

输入: [4,5,6,7,0,1,2]
输出: 0
题解
class Solution(object):
    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 特判
        if len(nums) == 1:
            return nums[0]
        
        # 左右指针
        left = 0
        right = len(nums) - 1

        # 如果最后一个元素大于第一个元素,那么该数组没有旋转,直接返回最小值
        if nums[right] > nums[0]:
            return nums[0]


        
        while right >= left:
            
            # 找中间元素
            mid = (left + right)//2

            # 如果中间的元素大于下一个元素,那么下一个元素就是旋转之后的部分 最小的元素就是mid+1
            if nums[mid] >  nums[mid + 1]:
                return nums[mid +1]
            
            # 如果中间的元素小于前一个元素 那么最小的元素就是中间的元素
            if nums[mid - 1] > nums[mid]:
                return nums[mid]
            # 如果中间的元素大于数组的第一个元素,那么最小的元素就在0-mid之间,改变left
            if nums[mid] > nums[0]:
                left = mid +1
            # 如果中间的元素小于数组的第一个元素,那么最小的元素就在mid-right之间,改变left
            else:
                right = mid + 1

350. 两个数组的交集 II

题目描述

给定两个数组,编写一个函数来计算它们的交集。

示例 1:

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

示例 2:

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
题解
class Solution(object):
    def intersect(self, nums1, nums2):
        """
        快慢指针
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        # 对两个数组进行排序
        nums1.sort()
        nums2.sort()

        # 利用两个指针来表示nums1与nums2的索引
        p_nums1,p_nums2 = 0 , 0
		# 保存交集
        result = []
        
        size1,size2 = len(nums1),len(nums2)
        # 循环
        while p_nums1 < size1 and p_nums2 < size2:
            # p_nums1比较小 移动p_nums1指针
            if nums1[p_nums1] < nums2[p_nums2]:
                p_nums1 += 1
            #如果相等 添加到result 并且移动p_nums1、p_nums2
            elif nums1[p_nums1] == nums2[p_nums2]:
                result.append(nums1[p_nums1])
                p_nums1 += 1
                p_nums2 += 1
            # p_nums1比较大 移动p_nums2指针
            else:
                p_nums2 += 1
        return result

56. 合并区间

题目描述

给出一个区间的集合,请合并所有重叠的区间。

示例 1:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
题解
class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        # 对区间进行排序
        intervals = sorted(intervals)
        n = len(intervals)
        i = 0
        res = []

        while i < n:
            left = intervals[i][0]
            right = intervals[i][1]
            # 如果一个区间的最小值小于前一个区间的最大值,两个区间合并
            while i < n - 1 and intervals[i+1][0] <= right:
                i += 1
                # 更新区间的最大值
                right = max(intervals[i][1],right)
            # 添加到res
            res.append([left,right])
            i+= 1
        return res

69. x 的平方根

题目描述

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去

示例 1:

输入: 4
输出: 2

示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 
     由于返回类型是整数,小数部分将被舍去。
题解
class Solution:
    def mySqrt(self, x ) :
        if x == 0:
            return 0

        left = 1
        right = x // 2

        while left < right:
            # 注意:这里一定取右中位数,如果取左中位数,代码可能会进入死循环
            mid = left + (right - left + 1) // 2
			
            # 判断square与x的大小,如果小的话 直接取mid(右中位数)
            square = mid * mid
            if square > x:
                right = mid - 1
            else:
                left = mid
        # 因为一定存在,因此无需后处理
        return left
个人总结 ,如有错误,请批评指正!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值