二分查找
两道题都是旋转数组,153返回最小值,33返回要找的目标值。
153. 寻找旋转排序数组中的最小值(无重复)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
154. 寻找旋转排序数组中的最小值 II 剑指11(有重复)
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/
二分查找的变形,注意到旋转数组的首元素肯定不小于旋转数组的尾元素,设置中间点。
如果中间点大于首元素,说明最小数字在后面一半,如果中间点小于尾元素,说明最小数字在前一半。依次循环。同时,当一次循环中首元素小于尾元素,说明最小值就是首元素。
但是当首元素等于尾元素等于中间值,只能在这个区域顺序查找。
1、中值 > 右值,最小值在右半边,收缩左边界
[3, 4, 5, 1, 2]
if rotateArray[mid] > rotateArray[right]: left = mid
2、明确中值 < 右值,最小值在左半边,收缩右边界
[5, 1, 2, 3, 4]
elif rotateArray[mid] < rotateArray[right]:
或 elif rotateArray[mid] < rotateArray[left]:都行
right = mid
154有重复代码
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
minVal = rotateArray[0]
# 特例:排序数组本身,把前面0个元素搬到最后面(未反转)
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]
else:
while (right - left) > 1:
mid = (right + left) // 2
# mid处于第一区间,最小数在mid右侧,右移left
# [3, 4, 5, 1, 2]
if rotateArray[mid] > rotateArray[right]:
left = mid
# mid处于第二区间,最小数在mid左侧,左移right
# [5, 1, 2, 3, 4]
elif rotateArray[mid] < rotateArray[left]:
right = mid
# 特例:如果三个数相等,此事只能顺序查找
elif rotateArray[mid] == rotateArray[left] == rotateArray[right]:
flag = False
for i in range(1, len(rotateArray)):
if rotateArray[i] < minVal:
minVal = rotateArray[i]
right = i
flag = True
if flag == False:
right = 0
# 最小数在right指针所指的位置
minVal = rotateArray[right]
return minVal
Test = Solution()
print(Test.minNumberInRotateArray([3, 4, 5, 1, 2]))
print(Test.minNumberInRotateArray([1, 2, 3, 4, 5]))
print(Test.minNumberInRotateArray([1, 1, 1, 0, 1]))
print(Test.minNumberInRotateArray([1, 0, 1, 1, 1]))
print(Test.minNumberInRotateArray([1, 1, 1]))
print(Test.minNumberInRotateArray([]))
print(Test.minNumberInRotateArray([1]))
153无重复代码
class Solution(object):
def findMin(self, rotateArray):
if len(rotateArray) == 0:
return 0
left = 0
right = len(rotateArray) - 1
minVal = rotateArray[0]
# 特例:排序数组本身,把前面0个元素搬到最后面(未反转)
if rotateArray[left] < rotateArray[right]:
return rotateArray[left]
else:
while (right - left) > 1:
mid = (right + left) // 2
# mid处于第一区间,最小数在mid右侧,右移left
# [3, 4, 5, 1, 2]
if rotateArray[mid] > rotateArray[right]:
left = mid
# mid处于第二区间,最小数在mid左侧,左移right
# [5, 1, 2, 3, 4]
elif rotateArray[mid] < rotateArray[left]:
right = mid
# 特例:如果三个数相等,此事只能顺序查找
# elif rotateArray[mid] == rotateArray[left] == rotateArray[right]:
# flag = False
# for i in range(1, len(rotateArray)):
# if rotateArray[i] < minVal:
# minVal = rotateArray[i]
# right = i
# flag = True
# if flag == False:
# right = 0
# 最小数在right指针所指的位置
minVal = rotateArray[right]
return minVal
33. 搜索旋转排序数组(无重复)
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。你的算法时间复杂度必须是 O(log n) 级别。
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
class Solution(object):
def search(self, nums, target):
if len(nums) == 0:
return -1
l = 0
r = len(nums) - 1
while l < r:
mid = l + (r - l) // 2
if nums[mid] < nums[r]: # [mid, r]有序
if nums[mid] < target <= nums[r]:
l = mid + 1
else:
r = mid
else: # [l, mid]有序
if nums[l] <= target <= nums[mid]:
r = mid
else:
l = mid + 1
if nums[l] == target:
return l
else:
return -1
81. 搜索旋转排序数组 II(有重复)
https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/
输入: nums = [2,5,6,0,0,1,2], target = 0
输出: true
class Solution(object):
def search(self, nums, target):
if len(nums) == 0:
return False
l = 0
r = len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return True
if nums[mid] == nums[l] == nums[r]: # 关键
l += 1
r -= 1
elif nums[mid] >= nums[l]:
if nums[l] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
else:
if nums[mid] < target <= nums[r]:
l = mid + 1
else:
r = mid - 1
return False
nums = [1,3,1,1,1]
target = 3
s = Solution()
print(s.search(nums, target))
其他解法
# 中间元素和右边界比较
class Solution(object):
def search(self, nums, target):
if len(nums) == 0:
return False
l = 0
r = len(nums) - 1
while l < r:
# mid = l + (r - l + 1) // 2
mid = (l + r + 1) >> 1
if nums[mid] < nums[r]:
# 后面是有序的
# [2,3,4,5,5,6,6,7]
if nums[mid] <= target <= nums[r]:
l = mid
else:
r = mid - 1
elif nums[mid] > nums[r]:
# [3,4,5,5,6,6,7,2]
if nums[l] <= target <= nums[mid - 1]:
r = mid - 1
else:
l = mid
else:
assert nums[mid] == nums[r]
if nums[r] == target:
return True
# 右边不是才删除
r = r - 1
# 后处理
return nums[l] == target