Bird
Raised Fist0
Interview Prepmodified-binary-searcheasyAmazonGoogle

Count Occurrences in Sorted Array

Choose your preparation mode4 modes available
🎯
Count Occurrences in Sorted Array
easyBINARY_SEARCHAmazonGoogle

Imagine you have a sorted list of product IDs and want to quickly find how many times a particular product appears to manage inventory efficiently.

💡 This problem is about efficiently counting how many times a target appears in a sorted array. Beginners often struggle because they try to scan the entire array linearly, missing the power of binary search to find boundaries quickly.
📋
Problem Statement

Given a sorted array of integers and a target integer, return the number of times the target appears in the array. If the target is not present, return 0.

1 ≤ n ≤ 10^5-10^9 ≤ array elements, target ≤ 10^9Array is sorted in non-decreasing order
💡
Example
Input"nums = [1,2,2,2,3,4,5], target = 2"
Output3

The number 2 appears at indices 1, 2, and 3, so the count is 3.

  • Empty array → 0
  • Target smaller than all elements → 0
  • Target larger than all elements → 0
  • All elements are the target → n (length of array)
⚠️
Common Mistakes
Using linear scan instead of binary search

Code is too slow and may time out on large inputs

✅ Implement binary search to find boundaries

Incorrectly adjusting pointers in binary search (off-by-one errors)

Infinite loops or wrong boundaries found

✅ Carefully update left and right pointers and test edge cases

Not checking if target exists before calculating count

Returns incorrect positive count when target not present

✅ Check if left boundary <= right boundary before returning count

Using mid = (left + right) / 2 without overflow protection

Potential integer overflow in some languages

✅ Use mid = left + (right - left) / 2

Confusing bisect_left and bisect_right in Python

Incorrect count returned

✅ Use bisect_left for target and target+1 to get correct boundaries

🧠
Brute Force (Linear Scan)
💡 This approach exists to establish a baseline and ensure understanding of the problem before optimizing. It’s simple but inefficient for large inputs.

Intuition

Check every element in the array and count how many times the target appears.

Algorithm

  1. Initialize a count to zero.
  2. Iterate through each element in the array.
  3. If the element equals the target, increment the count.
  4. Return the count after the iteration completes.
💡 This algorithm is straightforward but can be slow because it checks every element even if the array is sorted.
</>
Code
def count_occurrences(nums, target):
    count = 0
    for num in nums:
        if num == target:
            count += 1
    return count

# Driver code
if __name__ == '__main__':
    nums = [1,2,2,2,3,4,5]
    target = 2
    print(count_occurrences(nums, target))  # Output: 3
Line Notes
count = 0Initialize count to track occurrences
for num in nums:Iterate over every element to check for target
if num == target:Check if current element matches target
count += 1Increment count when target found
public class CountOccurrences {
    public static int countOccurrences(int[] nums, int target) {
        int count = 0;
        for (int num : nums) {
            if (num == target) {
                count++;
            }
        }
        return count;
    }

    public static void main(String[] args) {
        int[] nums = {1,2,2,2,3,4,5};
        int target = 2;
        System.out.println(countOccurrences(nums, target)); // Output: 3
    }
}
Line Notes
int count = 0;Initialize count to zero before iteration
for (int num : nums)Loop through each element in the array
if (num == target)Check if current element equals target
count++;Increment count when target found
#include <iostream>
#include <vector>
using namespace std;

int countOccurrences(const vector<int>& nums, int target) {
    int count = 0;
    for (int num : nums) {
        if (num == target) {
            count++;
        }
    }
    return count;
}

int main() {
    vector<int> nums = {1,2,2,2,3,4,5};
    int target = 2;
    cout << countOccurrences(nums, target) << endl; // Output: 3
    return 0;
}
Line Notes
int count = 0;Initialize counter before loop
for (int num : nums)Range-based loop to check each element
if (num == target)Compare current element with target
count++;Increment count if target matches
function countOccurrences(nums, target) {
    let count = 0;
    for (const num of nums) {
        if (num === target) {
            count++;
        }
    }
    return count;
}

// Test
const nums = [1,2,2,2,3,4,5];
const target = 2;
console.log(countOccurrences(nums, target)); // Output: 3
Line Notes
let count = 0;Initialize count variable
for (const num of nums)Loop through each element in array
if (num === target)Check if element equals target
count++;Increment count when target found
⏱
Complexity
TimeO(n)
SpaceO(1)

We scan through the entire array once, so time is linear in array size. Space is constant as we only store a count.

💡 For n=100,000 elements, this means 100,000 checks, which can be slow in interviews or large datasets.
Interview Verdict: Accepted but inefficient for large inputs

This approach works but is too slow for large arrays, motivating better methods.

🧠
Binary Search for Left and Right Boundaries
💡 This approach leverages the sorted property to find the first and last occurrence of the target efficiently, reducing time complexity drastically.

Intuition

Use binary search twice: once to find the leftmost index of the target, and once to find the rightmost index. The count is the difference plus one.

Algorithm

  1. Define a helper function to find the left boundary (first occurrence) of the target using binary search.
  2. Define a helper function to find the right boundary (last occurrence) of the target using binary search.
  3. If the target is not found, return 0.
  4. Otherwise, return right boundary - left boundary + 1 as the count.
💡 The tricky part is adjusting binary search to find boundaries instead of just any occurrence.
</>
Code
def left_boundary(nums, target):
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return left

def right_boundary(nums, target):
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if nums[mid] <= target:
            left = mid + 1
        else:
            right = mid - 1
    return right

def count_occurrences(nums, target):
    left = left_boundary(nums, target)
    right = right_boundary(nums, target)
    if left <= right:
        return right - left + 1
    return 0

# Driver code
if __name__ == '__main__':
    nums = [1,2,2,2,3,4,5]
    target = 2
    print(count_occurrences(nums, target))  # Output: 3
Line Notes
left, right = 0, len(nums) - 1Initialize search boundaries
mid = left + (right - left) // 2Calculate mid to avoid overflow
if nums[mid] < target:Move left pointer if mid value less than target
else: right = mid - 1Move right pointer to narrow left boundary
if nums[mid] <= target:Adjust left pointer to find right boundary
return rightReturn index of right boundary
if left <= right:Check if target exists in array
return right - left + 1Calculate count from boundaries
public class CountOccurrences {
    private static int leftBoundary(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return left;
    }

    private static int rightBoundary(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return right;
    }

    public static int countOccurrences(int[] nums, int target) {
        int left = leftBoundary(nums, target);
        int right = rightBoundary(nums, target);
        if (left <= right) {
            return right - left + 1;
        }
        return 0;
    }

    public static void main(String[] args) {
        int[] nums = {1,2,2,2,3,4,5};
        int target = 2;
        System.out.println(countOccurrences(nums, target)); // Output: 3
    }
}
Line Notes
int left = 0, right = nums.length - 1;Initialize binary search boundaries
int mid = left + (right - left) / 2;Calculate mid index safely
if (nums[mid] < target)Shift left pointer if mid less than target
else { right = mid - 1; }Shift right pointer to find left boundary
if (nums[mid] <= target)Shift left pointer to find right boundary
return right;Return right boundary index
if (left <= right)Check if target exists in array
return right - left + 1;Calculate count from boundaries
#include <iostream>
#include <vector>
using namespace std;

int leftBoundary(const vector<int>& nums, int target) {
    int left = 0, right = (int)nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return left;
}

int rightBoundary(const vector<int>& nums, int target) {
    int left = 0, right = (int)nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] <= target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return right;
}

int countOccurrences(const vector<int>& nums, int target) {
    int left = leftBoundary(nums, target);
    int right = rightBoundary(nums, target);
    if (left <= right) {
        return right - left + 1;
    }
    return 0;
}

int main() {
    vector<int> nums = {1,2,2,2,3,4,5};
    int target = 2;
    cout << countOccurrences(nums, target) << endl; // Output: 3
    return 0;
}
Line Notes
int left = 0, right = (int)nums.size() - 1;Initialize search boundaries
int mid = left + (right - left) / 2;Calculate mid index safely
if (nums[mid] < target)Move left pointer if mid less than target
else { right = mid - 1; }Move right pointer to narrow left boundary
if (nums[mid] <= target)Adjust left pointer to find right boundary
return right;Return right boundary index
if (left <= right)Check if target exists
return right - left + 1;Calculate count from boundaries
function leftBoundary(nums, target) {
    let left = 0, right = nums.length - 1;
    while (left <= right) {
        let mid = left + Math.floor((right - left) / 2);
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return left;
}

function rightBoundary(nums, target) {
    let left = 0, right = nums.length - 1;
    while (left <= right) {
        let mid = left + Math.floor((right - left) / 2);
        if (nums[mid] <= target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return right;
}

function countOccurrences(nums, target) {
    const left = leftBoundary(nums, target);
    const right = rightBoundary(nums, target);
    if (left <= right) {
        return right - left + 1;
    }
    return 0;
}

// Test
const nums = [1,2,2,2,3,4,5];
const target = 2;
console.log(countOccurrences(nums, target)); // Output: 3
Line Notes
let left = 0, right = nums.length - 1;Initialize binary search boundaries
let mid = left + Math.floor((right - left) / 2);Calculate mid index safely
if (nums[mid] < target)Move left pointer if mid less than target
else { right = mid - 1; }Move right pointer to narrow left boundary
if (nums[mid] <= target)Adjust left pointer to find right boundary
return right;Return right boundary index
if (left <= right)Check if target exists
return right - left + 1;Calculate count from boundaries
⏱
Complexity
TimeO(log n)
SpaceO(1)

Each binary search runs in logarithmic time, and we do two searches, so total time is O(log n). Space is constant.

💡 For n=100,000, this means about 2 * 17 = 34 operations, which is very fast compared to linear scanning.
Interview Verdict: Accepted and efficient

This is the preferred approach in interviews for sorted arrays because it is both correct and efficient.

🧠
Using Built-in Binary Search Functions (Language Specific)
💡 This approach uses language-provided binary search utilities to find boundaries, reducing code complexity and potential bugs.

Intuition

Use built-in functions to find insertion points for target and target+1, then subtract to get count.

Algorithm

  1. Use built-in binary search to find the left insertion point of the target.
  2. Use built-in binary search to find the left insertion point of target + 1.
  3. Subtract the two insertion points to get the count of target occurrences.
  4. Return the count.
💡 This approach abstracts the boundary search into library calls, making code concise.
</>
Code
import bisect

def count_occurrences(nums, target):
    left = bisect.bisect_left(nums, target)
    right = bisect.bisect_left(nums, target + 1)
    return right - left

# Driver code
if __name__ == '__main__':
    nums = [1,2,2,2,3,4,5]
    target = 2
    print(count_occurrences(nums, target))  # Output: 3
Line Notes
import bisectImport Python's built-in binary search module
left = bisect.bisect_left(nums, target)Find left insertion point of target
right = bisect.bisect_left(nums, target + 1)Find left insertion point of target+1
return right - leftCount is difference between insertion points
import java.util.Arrays;

public class CountOccurrences {
    public static int countOccurrences(int[] nums, int target) {
        int left = Arrays.binarySearch(nums, target);
        if (left < 0) {
            return 0;
        }
        int right = left;
        // Move right pointer to last occurrence
        while (right + 1 < nums.length && nums[right + 1] == target) {
            right++;
        }
        return right - left + 1;
    }

    public static void main(String[] args) {
        int[] nums = {1,2,2,2,3,4,5};
        int target = 2;
        System.out.println(countOccurrences(nums, target)); // Output: 3
    }
}
Line Notes
int left = Arrays.binarySearch(nums, target);Use built-in binary search to find any occurrence
if (left < 0)If target not found, return 0
while (right + 1 < nums.length && nums[right + 1] == target)Expand right pointer to last occurrence
return right - left + 1;Calculate count from boundaries
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int countOccurrences(const vector<int>& nums, int target) {
    auto left = lower_bound(nums.begin(), nums.end(), target);
    auto right = lower_bound(nums.begin(), nums.end(), target + 1);
    return right - left;
}

int main() {
    vector<int> nums = {1,2,2,2,3,4,5};
    int target = 2;
    cout << countOccurrences(nums, target) << endl; // Output: 3
    return 0;
}
Line Notes
#include <algorithm>Include algorithms for binary search utilities
auto left = lower_bound(nums.begin(), nums.end(), target);Find left insertion point
auto right = lower_bound(nums.begin(), nums.end(), target + 1);Find insertion point for target+1
return right - left;Count is difference between iterators
function countOccurrences(nums, target) {
    function lowerBound(arr, target) {
        let left = 0, right = arr.length;
        while (left < right) {
            let mid = left + Math.floor((right - left) / 2);
            if (arr[mid] < target) left = mid + 1;
            else right = mid;
        }
        return left;
    }
    const left = lowerBound(nums, target);
    const right = lowerBound(nums, target + 1);
    return right - left;
}

// Test
const nums = [1,2,2,2,3,4,5];
const target = 2;
console.log(countOccurrences(nums, target)); // Output: 3
Line Notes
function lowerBound(arr, target)Helper to find left insertion point using binary search
while (left < right)Loop until search space is exhausted
if (arr[mid] < target) left = mid + 1;Move left pointer if mid less than target
return left;Return insertion index
⏱
Complexity
TimeO(log n)
SpaceO(1)

Built-in binary search functions run in logarithmic time. We call them twice, so total time is O(log n). Space is constant.

💡 This approach is both fast and concise, leveraging language features to reduce code complexity.
Interview Verdict: Accepted and concise

Using built-in functions is often preferred if allowed, as it reduces bugs and code length.

📊
All Approaches - One-Glance Tradeoffs
💡 In 95% of interviews, coding the binary search for boundaries approach is best due to its balance of clarity and efficiency.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Brute ForceO(n)O(1)NoN/AMention only - never code for large inputs
2. Binary Search for BoundariesO(log n)O(1)NoN/ACode this approach for best balance of speed and clarity
3. Built-in Binary Search FunctionsO(log n)O(1)NoN/AUse if allowed to simplify code and reduce bugs
💼
Interview Strategy
💡 Use this guide to understand the problem deeply, practice coding all approaches, and prepare to explain tradeoffs clearly in interviews.

How to Present

Step 1: Clarify the problem and constraints with the interviewer.Step 2: Describe the brute force approach and its inefficiency.Step 3: Introduce binary search to find left and right boundaries.Step 4: Code the binary search approach carefully.Step 5: Test with edge cases and discuss complexity.

Time Allocation

Clarify: 2min → Approach: 3min → Code: 10min → Test: 5min. Total ~20min

What the Interviewer Tests

The interviewer tests your understanding of binary search modifications, boundary conditions, and ability to optimize from brute force.

Common Follow-ups

  • What if the array is not sorted? → Use a hash map or sort first.
  • Can you find the count without two binary searches? → No, because you need both boundaries.
💡 These follow-ups test your adaptability and understanding of problem constraints.
🔍
Pattern Recognition

When to Use

1) Input array is sorted, 2) Need to count occurrences or find boundaries, 3) Target may appear multiple times, 4) Efficient O(log n) solution required

Signature Phrases

count occurrencessorted arrayfirst and last positionnumber of times target appears

NOT This Pattern When

Linear search problems or unsorted array counting problems are different and do not use binary search.

Similar Problems

Find First and Last Position of Element in Sorted Array - same boundary search techniqueSearch Insert Position - similar binary search for insertion points

Practice

(1/5)
1. Given the following code for finding a peak element, what is the final output when the input array is [1, 3, 2]?
def findPeakElement(nums):
    def binarySearch(low, high):
        if low == high:
            return low
        mid = (low + high) // 2
        if nums[mid] < nums[mid + 1]:
            return binarySearch(mid + 1, high)
        else:
            return binarySearch(low, mid)
    return binarySearch(0, len(nums) - 1)

print(findPeakElement([1, 3, 2]))
easy
A. None of the above
B. 0
C. 2
D. 1

Solution

  1. Step 1: Trace first call binarySearch(0, 2)

    mid = (0+2)//2 = 1; nums[1]=3, nums[2]=2; since 3 > 2, recurse binarySearch(0,1)
  2. Step 2: Trace second call binarySearch(0, 1)

    mid = (0+1)//2 = 0; nums[0]=1, nums[1]=3; since 1 < 3, recurse binarySearch(1,1)
  3. Step 3: Trace third call binarySearch(1, 1)

    low == high, return 1
  4. Final Answer:

    Option D -> Option D
  5. Quick Check:

    Returned index 1 corresponds to peak element 3 [OK]
Hint: Check mid and mid+1 comparison carefully [OK]
Common Mistakes:
  • Returning mid instead of low/high
  • Off-by-one in mid calculation
  • Confusing which half to recurse
2. Consider the following Python code implementing the min-heap approach to find the kth smallest element in a sorted matrix. Given the matrix [[1,3],[2,4]] and k = 3, what value does the function return?
easy
A. 2
B. 4
C. 3
D. 1

Solution

  1. Step 1: Initialize min-heap with first elements

    Push (1,0,0) and (2,1,0) into heap.
  2. Step 2: Extract elements until count == k

    Pop 1 (count=1), push 3 from row 0; pop 2 (count=2), push 4 from row 1; pop 3 (count=3), return 3.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Third smallest element is 3 [OK]
Hint: Trace heap pops and pushes carefully [OK]
Common Mistakes:
  • Off-by-one counting of popped elements
  • Returning wrong popped value
  • Confusing row and column indices
3. You are given two integers m and n representing the dimensions of a multiplication table where the value at row i and column j is i * j. Given an integer k, you need to find the k-th smallest number in this table. Which approach guarantees an optimal solution for large m and n?
easy
A. Use binary search on the value range with a counting function to find how many numbers are less than or equal to a candidate number.
B. Generate all values in the multiplication table, sort them, and return the k-th element.
C. Use dynamic programming to build up the table and find the k-th smallest number by merging sorted rows.
D. Use a greedy approach by iteratively selecting the smallest unvisited product until the k-th is found.

Solution

  1. Step 1: Understand the problem constraints

    The multiplication table is large (up to m*n), so generating and sorting all values is inefficient.
  2. Step 2: Recognize the binary search pattern on answer space

    Binary searching the value range [1, m*n] and counting how many numbers are ≤ mid allows efficient narrowing down to the k-th smallest number.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Counting function with binary search is standard for this problem [OK]
Hint: Binary search on values, not indices [OK]
Common Mistakes:
  • Trying to generate and sort entire table
  • Using DP or greedy that don't scale
4. You are given an array representing the days on which flowers bloom. You want to make m bouquets, each consisting of k adjacent flowers. What is the most efficient approach to find the minimum day by which you can make all bouquets?
easy
A. Apply binary search on the range of days and check feasibility for each mid value.
B. Use a greedy approach to pick the earliest blooming flowers until bouquets are formed.
C. Use dynamic programming to track the minimum days for each bouquet count.
D. Sort the bloom days and pick the first m*k flowers directly.

Solution

  1. Step 1: Understand the problem constraints

    We need to find the minimum day such that we can form m bouquets of k adjacent flowers. The days range from min to max bloom day.
  2. Step 2: Recognize the pattern

    Binary searching over the answer space (days) and checking feasibility for each candidate day efficiently narrows down the minimum day. Greedy or sorting alone do not guarantee correctness because adjacency and feasibility must be checked.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Binary search on answer space is the standard pattern for such minimum day feasibility problems. [OK]
Hint: Binary search on answer space fits minimum day feasibility problems [OK]
Common Mistakes:
  • Thinking greedy or sorting alone solves adjacency constraints
  • Using DP unnecessarily complicates the problem
5. Examine the following buggy code snippet for the Split Array Largest Sum problem. Which line contains the subtle bug that can cause incorrect results or infinite loops?
medium
A. Line 7: Missing update of start to end causing infinite loop
B. Line 2: Initialization of count variable
C. Line 5: Using bisect_right to find end index
D. Line 8: Checking if count exceeds m

Solution

  1. Step 1: Analyze loop control variables

    The variable start controls the loop progress and must be updated to avoid infinite loops.
  2. Step 2: Identify missing update

    Line 7 lacks start = end, so start never advances, causing infinite loop or wrong split counts.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Without updating start, loop never progresses [OK]
Hint: Check loop variables update carefully [OK]
Common Mistakes:
  • Forgetting to update loop index after binary search
  • Misusing bisect boundaries causing off-by-one errors
  • Incorrect initialization of count or start
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard