原题链接
第一眼看到这个题,本能的想到二分搜索。自己的解法是这样:
- 先找到最小的值反转后的的位置,例如题目中的数组[4,5,6,7,0,1,2]中0在第四位,记为cur = 4,如何寻找呢?
顺序找肯定是不可取的,但是我第一次没有转个来这个弯,居然采用顺序查找的方式(那为什么不直接顺序查找target呢?真是笨) - 找到cur的位置便可以使用经典的二分查找法,但必须在翻转前后的座标之间做一个转换,这个转换的工作在下面的代码里会有体现。
class Solution:
def search(self, nums: 'List[int]', target: 'int') -> 'int':
nums_L = len(nums)
cur = 0
for i in range(1, nums_L):
if nums[i] < nums[i - 1]:
cur = i
break
#上面求cur
if cur != 0:
Solution.tran_cur = Solution.tran_cur1
elif nums[0] < nums[nums_L -1]:
Solution.tran_cur = Solution.tran_cur2
else:
Solution.tran_cur = Solution.tran_cur3
#根据cur的不同选取不同的转换函数,实际上这一步可用方法二中的一行代码就可以替换掉
l_, r_ = (0), (nums_L - 1)
l, r = Solution.tran_cur(l_, nums_L, cur), Solution.tran_cur(r_, nums_L, cur)
while l_ <= r_:
mid_ = int((l_ + r_) / 2)
mid = Solution.tran_cur(mid_, nums_L, cur)
if nums[mid] == target:
return mid
elif nums[mid] < target:
l_ = mid_ + 1
l = Solution.tran_cur(l_, nums_L, cur)
else:
r_ = mid_ - 1
r = Solution.tran_cur(r_, nums_L, cur)
return -1
#下面是三个转换函数
def tran_cur1(i, nums_L, cur):
l = i - (nums_L - cur)
r = i + cur
if l >= 0 and l < nums_L:
return l
else:
return r
def tran_cur2(i, nums_L, cur):
return i
def tran_cur3(i, nums_L, cur):
return nums_L - i -1
不得不说,我自己都觉得这代码实在太他妈的啰嗦,但精简的代码毕竟都是由繁入简一步步得到的。别看这代码啰嗦,而且计算cur时还是暴力算的,但是居然还beat了leetcode上67%的人,我感觉直接找都应该比这个方法要快!下面贴一个根据评论区某位老兄的代码改来的python版代码,思路其实相同。
class Solution:
def search(self, nums: 'List[int]', target: 'int') -> 'int':
nums_L = len(nums)
lo, hi = 0, nums_L-1
#采用二分的方式来求翻转后数组中的最小值,
while lo<hi:
mid = int((lo+hi)/2)
if nums[mid]>nums[hi]: lo = mid+1
else: hi = mid
cur = lo
lo, hi = 0, nums_L-1
while lo <= hi:
mid = int((lo+hi)/2)
#下面这行代码便是翻转前后座标的转换,一行搞定,实在令人佩服!
realmid = (mid+cur)%nums_L
if nums[realmid]==target: return realmid
elif nums[realmid]<target: lo = mid+1
else: hi = mid-1
return -1
这题虽然不难,但是花的时间却真不少,感触也很深。做这种题目一般都是通过一个具体的实例来想一个较为通用的解法,很多时候思路对了,但是因为不能够覆盖的了所有的情况又会导致很多错误的出现,而这些错误往往会通过一些特殊的做法来解决,不仅导致代码量的增加,而且在解决的过程中,还有可能会引出其他的一些错误。