Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,4,4,5,6,7] might become:
[4,5,6,7,0,1,4] if it was rotated 4 times.[0,1,4,4,5,6,7] if it was rotated 7 times.Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].
Given the sorted rotated array nums that may contain duplicates, return the minimum element of this array.
You must decrease the overall operation steps as much as possible.
Example 1:
Input: nums = [1,3,5] Output: 1
Example 2:
Input: nums = [2,2,2,0,1] Output: 0
Constraints:
n == nums.length1 <= n <= 5000-5000 <= nums[i] <= 5000nums is sorted and rotated between 1 and n times.Follow up: This problem is similar to Find Minimum in Rotated Sorted Array, but nums may contain duplicates. Would this affect the runtime complexity? How and why?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the minimum value in a rotated sorted list involves checking every single number. We simply go through the list, number by number, and remember the smallest one we've seen so far. At the end, the smallest number we remembered is the answer.
Here's how the algorithm would work step-by-step:
def find_minimum_brute_force(numbers):
# Initialize minimum with the first element
current_minimum = numbers[0]
for index in range(1, len(numbers)):
# Compare current element with the current minimum
if numbers[index] < current_minimum:
# Update current_minimum if a smaller element is found
current_minimum = numbers[index]
return current_minimumThe core idea is to use a divide-and-conquer approach. We repeatedly cut the search space in half by strategically examining elements to guide our search towards the minimum, even when the numbers are potentially duplicated.
Here's how the algorithm would work step-by-step:
def find_minimum_in_rotated_sorted_array_ii(numbers):
start_index = 0
end_index = len(numbers) - 1
while start_index < end_index:
# If already sorted, the first element is the minimum.
if numbers[end_index] > numbers[start_index]:
return numbers[start_index]
# Remove duplicate elements to shrink the search space.
if numbers[start_index] == numbers[end_index]:
end_index -= 1
continue
middle_index = (start_index + end_index) // 2
# The minimum must be in the right half.
if numbers[middle_index] > numbers[end_index]:
start_index = middle_index + 1
# The minimum must be in the left half or is the middle.
else:
end_index = middle_index
return numbers[start_index]| Case | How to Handle |
|---|---|
| Empty array | Return a default value such as positive infinity or throw an exception as there is no minimum. |
| Array with one element | Return the single element directly as it's trivially the minimum. |
| Array is not rotated (already sorted in ascending order) | The binary search should still converge to the first element as the minimum. |
| Array with all identical elements | The algorithm should correctly handle the case where the left and right values are equal, potentially requiring linear search within that range. |
| Array with many duplicate elements concentrated in a small section | The algorithm's efficiency might degrade to O(n) in the worst-case scenario where many elements are the same, and a linear search is needed. |
| Integer overflow during midpoint calculation | Use `mid = left + (right - left) / 2` to avoid potential integer overflow. |
| Very large array (memory constraints) | The binary search algorithm already has logarithmic space complexity, making it suitable for large arrays, but external memory solutions could be considered if the array exceeds available memory. |
| Array rotated such that the minimum element is at the very beginning or very end | The binary search logic must correctly handle these rotation extremes to find the true minimum. |