题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
解题思路:
方法一:线性查找(暴力解法)
易知最小值所在的地方一定是数值阶跃的位置,因此可以直接对数组进行线性查找,若某处值小于前一个值,则该值即为数组最小值。
class Solution(object):
def minArray(self, numbers):
"""
:type numbers: List[int]
:rtype: int
"""
'''
线性查找
'''
pre=numbers[0]
for num in numbers:
if num<pre:
return num
pre=num
return numbers[0]
方法二:二分查找
考虑数组中的最后一个元素 x:在最小值右侧的元素,它们的值一定都小于等于 x;而在最小值左侧的元素,它们的值一定都大于等于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。
在二分查找的每一步中,左边界为low,右边界为high,区间的中点为 pivot,最小值就在该区间内。我们将中轴元素 numbers[pivot] 与右边界元素numbers[high] 进行比较,可能会有以下的三种情况:
- 第一种情况是 numbers[pivot] < numbers[high],这说明 numbers[pivot]是最小值右侧的元素,因此我们可以忽略二分查找区间的右半部分。
- 第二种情况是 numbers[pivot] > numbers[high],这说明 numbers[pivot]是最小值左侧的元素,因此我们可以忽略二分查找区间的左半部分。
- 第三种情况是 numbers[pivot]==numbers[high]。如下图所示,由于重复元素的存在,我们并不能确定 numbers[pivot] 究竟在最小值的左侧还是右侧,因此我们不能莽撞地忽略某一部分的元素。我们唯一可以知道的是,由于它们的值相同,所以无论 numbers[high] 是不是最小值,都有一个它的「替代品」numbers[pivot],因此我们可以忽略二分查找区间的右端点。
class Solution(object):
def minArray(self, numbers):
"""
:type numbers: List[int]
:rtype: int
"""
'''
二分查找
'''
low,high=0,len(numbers)-1
while low<high:
mid=low+(high-low)/2 #这里不写成(low+high)/2是为了防止溢出
#如果中间值大于最右端值,则最小值在右部分区间
if numbers[mid]>numbers[high]:
low=mid+1
#如果中间值小于最右端值,则最小值在左部分区间
elif numbers[mid]<numbers[high]:
high=mid #注意这里high=mid而不是mid-1因为mid出也可能是最小值
else:
high-=1
return numbers[low]
trick:mid=low+(high-low)/2不写成mid=(high+low)/2是为了防止溢出
由于数据问题该题使用暴力解法耗时更短