题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路
思路1
暴力解法:根据给定的数组特点,从左到右遍历数组元素,当首次遇到数组中某个元素比上一个元素小时,该元素就是我们需要的元素。
python代码
defminNumberInRotateArray(self, rotateArray):
if not rotateArray:
return 0
num = rotateArray[0]
for i in range(1,len(rotateArray)):
if rotateArray[i] >= num:
num = rotateArray[i]
else:
return rotateArray[i]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
思路2
思路1的做法太无脑,时间复杂度O(N)。旋转数组也算是一种排序数组,可以用二分法解题,使时间复杂度最低控制在O(lgN)。
由于最近递归用的比较多,本能的就想通过递归求解该题。具体思路是用变量mid定位到数组的中间位置,将数组头部的值与mid处的值进行比较,不断缩小数组。这里有两个需要注意的点:
1. 由于是旋转数组,缩小到最小的数组大小为2,且数组中第一个元素为数组中值最大的元素,第二个元素是数组中值最小的元素,最后返回第二个元素。
2. 当数组中包含重复元素,具体到代码中是:当mid处的值等于数组头部的值时,无法判断最小值位于mid左侧还是右侧,此时只能采取遍历的方式。
Python代码
def minNumberInRotateArray(self, rotateArray):
if not rotateArray:
return 0
if len(rotateArray)==2:
return rotateArray[1]
mid = int(len(rotateArray)/2)
if rotateArray[mid] > rotateArray[0]:
return self.minNumberInRotateArray(rotateArray[mid:])
elif rotateArray[mid] < rotateArray[0]:
return self.minNumberInRotateArray(rotateArray[:mid+1])
else:
for i in range(1,len(rotateArray)):
if rotateArray[i] < rotateArray[0]:
return rotateArray[i]
return rotateArray[0]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
思路3
思路3属于思路2的小优化,可以缩短代码的长度,但不能改变代码的时间复杂度。具体来说,当mid处的值等于数组头部的值时,即当代码需要遍历时,可用一行代码代替for循环:
def minNumberInRotateArray(self, rotateArray):
if not rotateArray:
return 0
if len(rotateArray)==2:
return rotateArray[1]
mid = int(len(rotateArray)/2)
if rotateArray[mid] > rotateArray[0]:
return self.minNumberInRotateArray(rotateArray[mid:])
elif rotateArray[mid] < rotateArray[0]:
return self.minNumberInRotateArray(rotateArray[:mid+1])
else:
return self.minNumberInRotateArray(rotateArray[1:])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
思路4
由于每次递归都需要传入数组,这无疑更占用存储空间,特别当数组特别长时。最后给出该方法的非递归版本,只有一个数组不变,变化的只有指向数组的指针指向。
def minNumberInRotateArray(self, rotateArray):
left = 0
right = len(rotateArray)-1
while left < right:
mid = int((left+right)/2)
if rotateArray[mid] > rotateArray[right]:
left = mid+1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
right -= 1
return rotateArray[left]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
虽然思路4代码简短,时间复杂度和空间复杂度都比较低,但是如果稍微不注意,还是会掉到小坑里,比如如果用mid处的值和数组左边的值比较,会有什么不同;else语句中如果不让right处的指向左移一位,而是让left处的指针右移一位会怎么样,都是需要稍加留意的地方。