leetcode33. Search in Rotated Sorted Array相同的思路,不同的复杂度

原题链接
第一眼看到这个题,本能的想到二分搜索。自己的解法是这样:

  1. 先找到最小的值反转后的的位置,例如题目中的数组[4,5,6,7,0,1,2]中0在第四位,记为cur = 4,如何寻找呢?
    顺序找肯定是不可取的,但是我第一次没有转个来这个弯,居然采用顺序查找的方式(那为什么不直接顺序查找target呢?真是笨)
  2. 找到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

这题虽然不难,但是花的时间却真不少,感触也很深。做这种题目一般都是通过一个具体的实例来想一个较为通用的解法,很多时候思路对了,但是因为不能够覆盖的了所有的情况又会导致很多错误的出现,而这些错误往往会通过一些特殊的做法来解决,不仅导致代码量的增加,而且在解决的过程中,还有可能会引出其他的一些错误。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章