Taro Logo

Find Minimum in Rotated Sorted Array II

Hard
Amazon logo
Amazon
1 view
Topics:
ArraysBinary Search

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.

For example:

Example 1:

Input: nums = [1,3,5]

Output: 1

Example 2:

Input: nums = [2,2,2,0,1]

Output: 0

Can you provide an efficient algorithm to solve this problem, considering the presence of duplicates?

Solution


Brute Force Solution

The simplest approach is to iterate through the entire array and keep track of the minimum element encountered. This approach works regardless of whether the array is rotated or contains duplicates.

Algorithm

  1. Initialize min_element to the first element of the array.
  2. Iterate through the array from the second element.
  3. For each element, compare it with min_element. If the current element is smaller, update min_element.
  4. After iterating through the entire array, return min_element.

Code

def find_minimum_brute_force(nums):
    min_element = nums[0]
    for i in range(1, len(nums)):
        if nums[i] < min_element:
            min_element = nums[i]
    return min_element

Time Complexity

O(n), where n is the length of the array, as we iterate through the array once.

Space Complexity

O(1), as we use a constant amount of extra space to store the minimum element.

Optimal Solution: Binary Search

We can leverage binary search to find the minimum element more efficiently. The presence of duplicates makes the problem more challenging, as it may prevent us from discarding half of the array in each step.

Algorithm

  1. Initialize left to 0 and right to n - 1.
  2. While left < right:
    • Calculate mid = (left + right) // 2.
    • If nums[mid] > nums[right], then the minimum element must be in the right half of the array. Update left = mid + 1.
    • If nums[mid] < nums[right], then the minimum element must be in the left half of the array (including mid). Update right = mid.
    • If nums[mid] == nums[right], we cannot determine which half contains the minimum element. In this case, we simply decrement right to shrink the search space.
  3. Return nums[left]. At the end of the loop, left and right will point to the same index, which contains the minimum element.

Code

def find_minimum_binary_search(nums):
    left = 0
    right = len(nums) - 1

    while left < right:
        mid = (left + right) // 2

        if nums[mid] > nums[right]:
            left = mid + 1
        elif nums[mid] < nums[right]:
            right = mid
        else:
            right -= 1  # nums[mid] == nums[right]

    return nums[left]

Time Complexity

The worst-case time complexity is O(n), which occurs when the array contains many duplicate elements. In the worst case, nums[mid] == nums[right] repeatedly, and we reduce the search space by only one element in each step. However, in many cases, the time complexity will be better than O(n), potentially approaching O(log n) if duplicates are rare.

Space Complexity

O(1), as we use a constant amount of extra space to store the indices left, right, and mid.

Edge Cases

  • Empty Array: The problem statement specifies that 1 <= n <= 5000, so we don't need to handle an empty array explicitly. However, it's good to be aware of such edge cases during an interview.
  • Single Element Array: The algorithm works correctly for an array with a single element, as the while loop will not execute, and the function will return the single element.
  • Array with All Duplicate Elements: The algorithm will still work correctly, although the time complexity will be O(n) in this case.
  • Already Sorted Array: If the array is already sorted (i.e., not rotated), the algorithm will still find the minimum element, as nums[mid] < nums[right] will be true in the first iteration, and right will be updated to mid until left == right.