程序员面试金典里的解法才是正解,逻辑上没有漏洞,其他书籍的解法是有问题的:
无论数组是否有相同数字。都可以使用下面解法:
def search(arr, left, right, x): if left > right: return -1 mid = (left+right)/2 if x == mid: return mid # 你先看下最外围的三个if, 逻辑完备,>, <, = 都考虑到了!!! if arr[left] < arr[mid]: # 再看里面的if,都是在确定究竟哪一段有序 if x>= arr[left] and x<arr[mid]: return search(arr, left, mid-1, x) else: return search(arr, mid+1, right, x) elif arr[mid] < arr[left]: if x>arr[mid] and x<=arr[right]: return search(arr, mid+1, right, x) else: return search(arr, left, mid-1, x) else: if arr[mid] == arr[right]: # 说明arr[mid]==arr[left]==arr[right],两边都有相等数据,只能两边继续二分 result = search(arr, left, mid-1, x) if result == -1: return search(arr, mid+1, right, x) else: return result else: # 说明 arr[mid]!=arr[right],仅left这边遇到相等 return search(arr, mid+1, right, x)
这段代码非常关键:
else: if arr[mid] == arr[right]: # 说明arr[mid]==arr[left]==arr[right],两边都有相等数据,只能两边继续二分 result = search(arr, left, mid-1, x) if result == -1: return search(arr, mid+1, right, x) else: return result else: # 说明 arr[mid]!=arr[right],仅left这边遇到相等 return search(arr, mid+1, right, x)
同理,对于求解旋转数组最小值的解法:
def get_min_of_rotation(arr, left, right): assert left <= right if left == right: return arr[left] mid = (left+right)/2 if arr[mid] > arr[left]: return min(arr[left], get_min_of_rotation(arr, mid+1, right)) elif arr[mid] < arr[left]: return min(arr[mid], get_min_of_rotation(arr, left, mid-1)) else: if arr[mid] != arr[right]: return min(arr[mid], get_min_of_rotation(arr, mid+1, right)) else: return min(arr[mid], get_min_of_rotation(arr, mid+1, right), get_min_of_rotation(arr, left, mid-1))