NC105 二分查找进阶

描述
请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1

数据范围:
进阶:时间复杂度,空间复杂度
示例1
输入:
[1,2,4,4,5],4
返回值:
2
说明:
从左到右,查找到第1个为4的,下标为2,返回2
示例2
输入:
[1,2,4,4,5],3
返回值:
-1
示例3
输入:
[1,1,1,1,1],1
返回值:
0
**方法一:**直接遍历 不用二分查找 这样不需要考虑特殊情况
**方法二:**利用二分查找 分两段的形式完成 但是如果像 11111这种情况就找不到最小的index
采用了递归的方式的代码为:

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 如果目标值存在返回下标,否则返回 -1
# @param nums int整型一维数组 
# @param target int整型 
# @return int整型
#
class Solution:
    def search(self , nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) - 1
        ind = self.searchtwo(start, end, nums, target)
        return ind
    def searchtwo(self, start, end , nums, target):
        mid = int((start + end) / 2)
        while start <= end:
            if target < nums[mid]:
                end = mid - 1
                return self.searchtwo(start, end , nums, target)
            elif target == nums[mid]:
                # 往前看是否还有更靠前的index
                i = mid - 1
                while i >= 0:
                    if nums[i] == target:
                        mid = i
                    i = i - 1
                return mid
            elif target > nums[mid]:
                start = mid + 1
                return self.searchtwo(start, end , nums, target)
        return -1

这里需要注意的就是:
1)递归的时候,每一种可能性都要有一个return
2)进行递归的条件是start <= end: 保证在数组中没有这个值的时候,跳出循环,返回-1
3)在更改start和 end的时候,一定是 mid + 1 或者mid -1 不然while循环永远也跳不出去,比如说找不到的时候就会一直不断赋值。
但是这种方法在遇到 [1, 1, 1, 1, 1]这种情况会导致还是要往前遍历找到最小的index,故时间复杂度为O(n)。
!!! 还要注意考虑长度为0的情况

**方法三:**减少时间复杂度,令时间复杂度为O(log n)
trick: 将while循环的条件改为start < end,故当start = end 时不能进入循环,这时只需要判断 index为 start或者end时,是否为target,证明当为target时就返回index不然就返回-1,这样就避免了再次往前遍历的情况。
故 方法二的形式只能说查找到,但是不一定找到对小的index。

  1. 用递归的方式的:
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 如果目标值存在返回下标,否则返回 -1
# @param nums int整型一维数组 
# @param target int整型 
# @return int整型
#
class Solution:
    def search(self , nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) - 1
        ind = self.searchtwo(start, end, nums, target)
        return ind
    def searchtwo(self, start, end , nums, target):
        if end < 0:
            return -1
        mid = int((start + end) / 2)
        while start < end:
            if target < nums[mid]:
                end = mid - 1
                return self.searchtwo(start, end , nums, target)
            elif target == nums[mid]:
                end = mid
                return self.searchtwo(start, end, nums, target)
            elif target > nums[mid]:
                start = mid + 1
                return self.searchtwo(start, end , nums, target)
        if nums[start] == target:
            return start
        else:
            return -1

不用递归的方式的:

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 如果目标值存在返回下标,否则返回 -1
# @param nums int整型一维数组 
# @param target int整型 
# @return int整型
#
class Solution:
    def search(self , nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) - 1
        ind = self.searchtwo(start, end, nums, target)
        return ind
    def searchtwo(self, start, end , nums, target):
        if end < 0:
            return -1
        while start < end:
            mid = int((start + end) / 2)
            if target < nums[mid]:
                end = mid - 1
            elif target == nums[mid]:
                end = mid
            elif target > nums[mid]:
                start = mid + 1
        if nums[start] == target:
            return start
        else:
            return -1

其他人比较好的:
没有用递归的方式的:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();
        if(n < 1 || nums[0] > target || nums[n - 1] < target) {
            return -1; //数组为空,数组中所有元素都大于/小于目标值时,直接返回-1
        }
        int i = 0, j = n - 1, mid = 0;
        while(i < j) {
            mid = (i + j) / 2;
            if(nums[mid] < target) {
                i = mid + 1;
            } else if(nums[mid] > target) {
                j = mid - 1;
            } else {
                j = mid;//为避免丢失答案,不能为mid-1
            }
        }
        return nums[i] == target ? i : -1; //最后进行一次判断
    }
};

如果求最大的index的话,不仅要把end = mid 部分改成start = mid,还要把每次求mid值后面+ 1,因为不然的话就会一直start为一个小的index,一直陷入while循环里,因为每次的0.5都舍去了,导致无法走出循环:

from typing import List
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 如果目标值存在返回下标,否则返回 -1
# @param nums int整型一维数组
# @param target int整型
# @return int整型
#
class Solution:
    def search(self , nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) - 1
        ind = self.searchtwo(start, end, nums, target)
        return ind
    def searchtwo(self, start, end , nums, target):
        if end < 0:
            return -1
        mid = int((start + end) / 2) + 1
        while start < end:
            if target < nums[mid]:
                end = mid - 1
                return self.searchtwo(start, end , nums, target)
            elif target == nums[mid]:
                start = mid
                return self.searchtwo(start, end, nums, target)
            elif target > nums[mid]:
                start = mid + 1
                return self.searchtwo(start, end, nums, target)
        if nums[start] == target:
            return start
        else:
            return -1


if __name__ == '__main__':
    a = Solution()
    list = [1, 1, 1, 1, 1]
    b = a.search(list, 1)
    print(b)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值