原題鏈接
第一眼看到這個題,本能的想到二分搜索。自己的解法是這樣:
- 先找到最小的值反轉後的的位置,例如題目中的數組[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
這題雖然不難,但是花的時間卻真不少,感觸也很深。做這種題目一般都是通過一個具體的實例來想一個較爲通用的解法,很多時候思路對了,但是因爲不能夠覆蓋的了所有的情況又會導致很多錯誤的出現,而這些錯誤往往會通過一些特殊的做法來解決,不僅導致代碼量的增加,而且在解決的過程中,還有可能會引出其他的一些錯誤。