Start learning free

LESSON 270 OF 410 · BINARY SEARCH

Number of Occurrences in Sorted Array in O(log n) Time Using Python

Practice O(log n) Read the full explanation

Given a sorted array of integers nums, count the number of occurrences of a given value.

Example:

Input: nums = [1, 2, 2, 2, 4, 5], value = 2
Output: 3
Explanation: the value 2 appears 3 times in the array

Note:

Your algorithm should run in O(log n) time and use O(1) extra space.


Hints:

If value exists in nums, it will occur in a subarray of consecutive elements. If we manage to find this subarray, we'll also know the number of occurrences of value.

This subarray is determined by the first and last indices where value occurs in nums. How would you find the first occurrence in O(log n) time?

We can find the first occurrence using an algorithm we have already studied: Lower Bound.
Can you write a similar binary search algorithm for finding the last occurrence of value in nums?


We will implement a binary search and use a variable ans to store the best answer found so far, just like we did in Lower Bound. The only difference is how we handle the cases for each mid index. What should we do if:
  • the element at index mid is greater than value?
  • the element at index mid is less than or equal to value?


  • If the element at index mid is greater than value, we should continue the search in the part of nums from left to mid - 1, e.g. set right to mid - 1
  • If the element at index mid is less than or equal to value, we should set ans to mid and continue the search in the part of nums from mid + 1 to right, e.g. set left to mid + 1

STEP 1 OF 10
    Ctrl + Enter to check

    PYTHON · BINARY SEARCH

    Number Of Occurrences in Python, explained

    Understanding the Problem

    The core challenge of this problem is to count the occurrences of a given value in a sorted array efficiently. The significance of this problem lies in its applications in search algorithms and data analysis where quick lookups are essential. A common pitfall is to use a linear search which would result in O(n) time complexity, which is not optimal for large datasets.

    Approach

    To solve this problem efficiently, we can use binary search to find the first and last occurrences of the given value. The difference between these indices plus one will give us the count of occurrences.

    Naive Solution

    A naive solution would be to iterate through the array and count the occurrences of the value. This would take O(n) time, which is not efficient for large arrays.

    Optimized Solution

    We can use binary search to find the first and last occurrences of the value. This approach will take O(log n) time, which is optimal for this problem.

    Finding the First Occurrence

    We can use a modified binary search to find the first occurrence of the value. If the middle element is greater than or equal to the value, we move to the left half; otherwise, we move to the right half.

    Finding the Last Occurrence

    Similarly, we can use a modified binary search to find the last occurrence of the value. If the middle element is less than or equal to the value, we move to the right half; otherwise, we move to the left half.

    Algorithm

    Here is a step-by-step breakdown of the algorithm:

    1. Initialize two functions to find the first and last occurrences of the value using binary search.
    2. In the first occurrence function, if the middle element is greater than or equal to the value, move to the left half; otherwise, move to the right half.
    3. In the last occurrence function, if the middle element is less than or equal to the value, move to the right half; otherwise, move to the left half.
    4. Calculate the number of occurrences by subtracting the first index from the last index and adding one.

    Code Implementation

    def find_first_occurrence(nums, value):
        left, right = 0, len(nums) - 1
        first_occurrence = -1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] >= value:
                if nums[mid] == value:
                    first_occurrence = mid
                right = mid - 1
            else:
                left = mid + 1
        return first_occurrence
    
    def find_last_occurrence(nums, value):
        left, right = 0, len(nums) - 1
        last_occurrence = -1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] <= value:
                if nums[mid] == value:
                    last_occurrence = mid
                left = mid + 1
            else:
                right = mid - 1
        return last_occurrence
    
    def count_occurrences(nums, value):
        first_occurrence = find_first_occurrence(nums, value)
        if first_occurrence == -1:
            return 0
        last_occurrence = find_last_occurrence(nums, value)
        return last_occurrence - first_occurrence + 1
    
    # Example usage
    nums = [1, 2, 2, 2, 4, 5]
    value = 2
    print(count_occurrences(nums, value))  # Output: 3
    

    Complexity Analysis

    The time complexity of both the first and last occurrence functions is O(log n) because we are using binary search. The space complexity is O(1) as we are not using any extra space.

    Edge Cases

    Some potential edge cases include:

    • The value does not exist in the array. The function should return 0.
    • All elements in the array are the same as the value. The function should return the length of the array.
    • The array is empty. The function should return 0.

    Testing

    To test the solution comprehensively, we should include a variety of test cases:

    • Simple cases with a few elements.
    • Cases where the value does not exist in the array.
    • Cases with large arrays to test the efficiency.
    • Edge cases as mentioned above.

    Thinking and Problem-Solving Tips

    When approaching such problems, it is essential to:

    • Understand the problem requirements and constraints.
    • Think about the most efficient way to solve the problem.
    • Break down the problem into smaller sub-problems.
    • Consider edge cases and test your solution thoroughly.

    Conclusion

    In this blog post, we discussed how to count the number of occurrences of a value in a sorted array efficiently using binary search. We provided a detailed explanation of the algorithm, code implementation, and complexity analysis. Understanding and solving such problems is crucial for improving problem-solving skills and preparing for coding interviews.

    Additional Resources

    For further reading and practice problems, consider the following resources:

    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free