'''
154_尋找旋轉排序陣列中的最小值 ii
假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。
( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。
請找出其中最小的元素。
注意陣列中可能存在重複的元素。
示例 1:
輸入: [1,3,5]
輸出: 1
示例 2:
輸入: [2,2,2,0,1]
輸出: 0
說明:這道題是 尋找旋轉排序陣列中的最小值的延伸題目。
允許重複會影響演算法的時間複雜度嗎?會如何影響,為什麼?
'''class solution:
'''演算法1:真正的二分查詢,特殊情況是nums[l] == nums[m] == nums[r],此時無法判斷哪一側是純遞增的。
遞迴處理特殊情況,返回最小值,其他情況照搬無重複值迴圈遞增陣列的做法,消除了尾遞迴
執行用時 :128 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.7 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin(self, nums: list) -> int:
def ans(l, r):
if l + 1 == r: #單獨判斷只有2個元素的情形,以避免死迴圈
return min(nums[l], nums[r])
while l < r:
m = (l + r) // 2
if nums[l] == nums[m] == nums[r]:
return min(ans(l, m-1), ans(m, r))
elif nums[m] <= nums[r]:
r = m
else:
l = m + 1
return nums[r]
return ans(0, len(nums)-1)
'''演算法2:演算法1的另一種寫法,沒有消除尾遞迴
執行用時 :148 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.7 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin2(self, nums: list) -> int:
def ans(l, r):
m = (l + r) // 2
if l == r:
return nums[l]
elif l + 1 == r:
return min(nums[l], nums[r])
elif nums[l] == nums[m] == nums[r]:
return min(ans(l, m-1), ans(m, r))
elif nums[m] <= nums[r]:
return ans(l, m)
else:
return ans(m+1, r)
return ans(0, len(nums)-1)
'''其他情況則照搬無重複值迴圈遞增陣列的做法,實行對分查詢。效率不如演算法1高,但是**更簡潔。
執行用時 :136 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.7 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin3(self, nums: list) -> int:
l, r = 0, len(nums)-1
while l < r:
m = (l + r) // 2
if nums[l] == nums[m] == nums[r]:
l += 1 #或r -= 1
elif nums[m] <= nums[r]:
r = m
else:
l = m + 1
return nums[r]
'''演算法4:對演算法3的條件語句做了乙個順序上的調整,也許效率更高
執行用時 :132 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.2 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin4(self, nums: list) -> int:
l, r = 0, len(nums)-1
while l < r:
m = (l + r) // 2
if nums[m] > nums[r]:
l = m + 1
elif nums[m] < nums[r]:
r = m
else:
r -= 1
return nums[r]
'''演算法5:演算法3的乙個變式,確保迴圈體內至少有3個元素,這樣當nums[l] == nums[m] == nums[r]時,左右邊界均可向中間移動1位,
最後剩下2個元素,輸出最小值
執行用時 :132 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.2 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin5(self, nums: list) -> int:
l, r = 0, len(nums)-1
while l + 1 < r:
m = (l + r) // 2
if nums[l] == nums[m] == nums[r]:
l, r = l + 1, r - 1
elif nums[m] <= nums[r]:
r = m
else:
l = m + 1
return min(nums[l], nums[r])
'''演算法6:對演算法5的條件語句做了乙個順序上的調整,也許效率更高
執行用時 :132 ms, 在所有 python3 提交中擊敗了5.94%的使用者
記憶體消耗 :29.2 mb, 在所有 python3 提交中擊敗了5.01%的使用者
'''def findmin6(self, nums: list) -> int:
l, r = 0, len(nums)-1
while l + 1 < r:
m = (l + r) // 2
if nums[m] > nums[r]:
l = m + 1
elif nums[l] == nums[m] == nums[r]:
l, r = l + 1, r - 1
else:
r = m
return min(nums[l], nums[r])
x = solution()
a = [3,4,5,1,2]
print(x.findmin(a), x.findmin2(a), x.findmin3(a), x.findmin4(a), x.findmin5(a), x.findmin6(a))
a = [1,3,3]
print(x.findmin(a), x.findmin2(a), x.findmin3(a), x.findmin4(a), x.findmin5(a), x.findmin6(a))
154 尋找旋轉排序陣列中的最小值 II H
假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。例如,陣列 0,1,2,4,5,6,7 可能變為 4,5,6,7,0,1,2 請找出其中最小的元素。注意陣列中可能存在重複的元素。示例 1 輸入 1,3,5 輸出 1 示例 2 輸入 2,2,2,0,1 輸出 0 說明 這道題是 尋找旋轉排序陣...
154尋找旋轉排序陣列中的最小值 II
題目描述 假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。例如,陣列 0,1,2,4,5,6,7 可能變為 4,5,6,7,0,1,2 請找出其中最小的元素。注意陣列中可能存在重複的元素。示例 1 輸入 1,3,5 輸出 1 示例 2 輸入 2,2,2,0,1 輸出 0 說明 這道題是 尋找...
154 尋找旋轉排序陣列中的最小值 II
題目描述 假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。例如,陣列 0,1,2,4,5,6,7 可能變為 4,5,6,7,0,1,2 請找出其中最小的元素。注意陣列中可能存在重複的元素。示例 1 輸入 1,3,5 輸出 1 示例 2 輸入 2,2,2,0,1 輸出 0 說明 題解 二分。二...