描述
请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)长度为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
# @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)