这些是关联的近似题目,都是查找数字,只是条件略有不同:
0153:找最小值,数组的的值互不相同
0154:找最小值,数组中存在相同值
0033:找目标值,数组中的值互不相同
0081:找目标值,数组中存在相同值
10.03:与81相同, 区别在于返回找的第一个索引
- 搜索旋转排序数组
class No_0033_Search:
"""
题干:
https://leetcode.cn/problems/search-in-rotated-sorted-array/
整数数组nums按升序排列,数组中的值互不相同,在 旋转后的数组 中搜索整数target
解析:
对“有序数组”,基本思路是二分查找。
数组轮转后有以下两种情况(*号表示最小值, |表示中间位置),
通过 当前的边界值 与 当前中间值 对比,可以区分这两种情况:
• 数组的起始值(最小值)在左半部分: [6, 7, 8 *1, | 2, 3, 4, 5]
则数组的右半部分保持有序状态
• 数组的起始值(最小值)在右半部分: [4, 5, 6, 7, | 8, *1, 2, 3]
则数组的左半部分保持有序状态
• 判断target是否在被包含在有序区间内,从而收缩查找范围
"""
def __relative_links__(self):
"""关键字:旋转数组/二分查找"""
link1 = No_0153_FindMin # 值互不相同
link2 = No_0154_FindMin2 # 存在相同值
link3 = No_0033_Search # 值互不相同
link4 = No_0081_Search2 # 存在相同值
link5 = Job_10_03_loop_list # 与81基本接近,区别在于返回第一个索引
@staticmethod
def sol_01_dichotomy(nums, target):
n = len(nums)
left, right = 0, n-1
# 控制条件取等号,在while中直接return mid。
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
# 中间值为target,直接返回
return mid
if nums[left] <= nums[mid]:
# 左半部分有序
if nums[left] <= target < nums[mid]:
# target落在左半部分有序区域内
right = mid-1
else:
# target落在右半部分无序区域内
left = mid+1
else:
# 右半部分有序
if nums[mid] < target <= nums[len(nums)-1]:
# target落在右半部分有序区域内
left = mid+1
else:
# target落在左半部分无序区域内
right = mid-1
return -1
- 搜索旋转排序数组 II
class No_0081_Search2:
"""
题干:
https://leetcode.cn/problems/search-in-rotated-sorted-array-ii/
寻找旋转排序数组中的值
解析:
有序数组的基本思路是二分查找。
对于数组中有重复元素的情况,二分查找时可能会有 a[l]=a[mid]=a[node],
此时无法判断左区间a[l:mid]和右区间a[mid:node+1]哪个是有序的,譬如:
[1, 1, 2, 3 *1, 1 | 1, 1, 1, 1, 1, 1]
对于这种情况,我们将当前二分区间的左边界加一,右边界减一,然后在新区间上继续二分查找。
1, [1, 2, 3 *1, 1 | 1, 1, 1, 1, 1] , 1
"""
@staticmethod
def sol_01_dichotomy(nums, target):
n = len(nums)
left, right = 0, n-1
# 控制条件取等号,在while中直接return mid。
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
# 中间值即为target,直接返回
return True
if nums[left] == nums[mid] == nums[right]:
# 收缩区间
left += 1
right -= 1
elif nums[left] <= nums[mid]:
# 左半部分有序
if nums[left] <= target < nums[mid]:
# target落在左半部分有序区域内
right = mid-1
else:
# target落在右半部分无序区域内
left = mid+1
else:
# 右半部分有序
if nums[mid] < target <= nums[len(nums)-1]:
# target落在右半部分有序区域内
left = mid+1
else:
# target落在左半部分无序区域内
right = mid-1
return False