二分查找汇总

序言

下面都是lt的关于二分查找的题目。 好好干饭,好好努力,好好加油哦!

题目一:最长公共前缀

找到几个字符串中最长公共前缀。

例子:

Input: ["flower","flow","flight"]
Output: "fl"
Input: ["dog","racecar","car"]
Output: ""

二分法思路:
首先公共前缀 肯定是最前面的几个字符才会叫做 前缀。
那么我们先把字符串组中的第一个字符串flower作为比较标准
先折半 变成 所以bgn=0,end= 6-1=5
折半mid = (0+5)//2=2,所以字符是flower[0:mid+1] = flo
检查是否都在所以的字符串里:
(1) flo 并不是都在,
end = mid -1 = 1 ; mid = (0+1)//2 = 0
所以这次字符串是 flower[0:mid+1] = f
(2) f 都在:
bgn = mid + 1 = 1 ; mid = (bgn + mid)//2 = 1
所以这次字符是 flower[0:mid+1] = fl
这个时候 bgn = end = 1 不应该再下一次了 所以终止条件是 while bgn < end

class Solution:
    def check(self,strs,tmp):
        for s in strs: 
           if s.find(tmp)!=0: return False 
        return True 

    def longestCommonPrefix(self, strs: List[str]) -> str:
        left = 0 
        right = len(strs[0]) -1 
        pivot = strs[0]
        while left <= right:
            mid = (left + right)//2
            tmp = pivot[0:mid+1]
            if self.check(strs,tmp):
                left = mid + 1
            else: right = mid -1 
         
        return pivot[0:right + 1] if right>=0 else ''

题目二:数组插入值

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置

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

思路是:
这里把题目转换一下,就是如果target比 数组的数都大的话,那么直接输出长度
否则的话,输出刚好比target大或者等于的数的index。

用二分法寻找
当bgn = end的时候 ,仍在在循环内,
如果target 大于 tmp的时候,即表示当前tmp小于target,需要往前一步再返回。
如果target 小于 tmp的时候,即表示当前的tmp都大于target,那直接返回bgn即可

二分法:

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

题目三:求开方跟

实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去

输入: 4
输出: 2
----------------
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

用二分法来做
把(0,x)中,即bgn = 0 ,end = x
mid = (bgn + end )//2 = x//2 tmp = mid * mid
比较 tmp和x 如果tmp大的话,则需要让mid变小,则 end要变小 即end变成 mid-1
比较 tmp和x 如果tmp小的话,则需要让mid 表大,则bgn 要变大,即bgn 变成 mid+1
if tmp = x则返回mid

最后结束之后,返回 end 为什么不返回 bgn 这是因为这次我们要返回的是更小的数,
如果是返回大的数,则返回bgn 返回小的数,返回end。

def mySqrt(x):
	bgn = 0
	end = x 
	while bgn <= end:
		mid = (bgn + end)//2
		tmp = mid*mid 
		if tmp > x: 
			end = mid - 1 
		elif tmp < x:
			bgn = mid + 1 
		else: 
			return mid 
	return end 

这道题也可以用牛顿法。
牛顿法的思想是
初始化某一个点,然后求这个点的切线之后,再求这个切线在横坐标的x 作为更新的值
终止条件是 连续的两个x值 相差极小 0.000001
这个方法肯定会超过规定的时间复杂度

def mySqrt(x):
	if x == 0: return x 
	#初始值 x0 = x
	x0 =x 
	while True:
		x1 = 1/2 * (x/x0 + x0)
		if abs(x1 - x0) < 0.000001:
			break 
		x0 =x1 
	return int(x0)

题目四:twoSum问题

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

之前用了哈希表来求,现在用二分法来做
思路是
现在有两个数,怎么用二分法呢? 思路是固定一个值,然后在剩下的数组中,寻找另一个值。用二分法来找

def twoSum(numbers, target):
	for i in range(len(numbers)):
		bgn = i 
		end = len(numbers) -1 
		while bgn <= end:
			mid = (bgn + end )//2
			tmp = numbers[mid]
			if tmp < target - numbers[i]:
				bgn = mid + 1 
			elif tmp > target - numbers[i]:
				end = mid - 1 
			elif tmp == target - numbers[i]: 
				return [i,mid]
		return []		

题目五:LT287-寻找重复值

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。
你设计的解决方案必须不修改数组 nums 且只用常量级 O(1) 的额外空间

输入:nums = [1,3,4,2,2]
输出:2

如果直接使用哈希表的话,时间复杂度和空间复杂度都是O(N),不能满足要求
如果用set函数的话,那也是占据O(N)的空间,也是不满足要求

所以这里有一个抽屉法的二分法。
举一个例子就是:在这里插入图片描述
cnt表示的是 比当前值小或者等于的个数有多少个。
比如 在这个例子中,bgn=1, end = 4 所以mid = (bgn + end)//2 = 2
所以在nums中,小于或者等于mid的有3个。3 > mid = 2 所以答案是 在 bgn ~ mid 之间。
如果大于mid的话,则在mid+1 ~ end之间。 最后返回bgn

class Solution:
    def cnt(self,nums,mid):
        cnt = 0 
        for num in nums:
            if num <= mid: cnt += 1 
        return cnt 

    def findDuplicate(self, nums: List[int]) -> int:
        #考虑抽屉的二分法
        #由于是1,2,3,4,n中有一个数是重复的是 所以 
        bgn = 1
        end = len(nums) - 1
        while bgn < end:
            mid =  (bgn + end)//2 
            cnt = self.cnt(nums,mid)
            if cnt > mid: end = mid
            else : bgn = mid + 1 
        return bgn 

这里的时间复杂度是 O(nlogn)
空间复杂度是O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值