Count Occurrences of Element in Sorted Array in DSA C# - Time & Space Complexity
We want to know how long it takes to count how many times a number appears in a sorted list.
How does the time needed change when the list gets bigger?
Analyze the time complexity of the following code snippet.
int CountOccurrences(int[] arr, int target) {
int first = FindFirst(arr, target);
if (first == -1) return 0;
int last = FindLast(arr, target);
return last - first + 1;
}
int FindFirst(int[] arr, int target) {
int low = 0, high = arr.Length - 1;
int result = -1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
result = mid;
high = mid - 1;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return result;
}
int FindLast(int[] arr, int target) {
int low = 0, high = arr.Length - 1;
int result = -1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
result = mid;
low = mid + 1;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return result;
}
This code finds the first and last positions of the target number using binary search, then calculates how many times it appears.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Binary search loops in FindFirst and FindLast methods.
- How many times: Each binary search loop runs about log₂(n) times, where n is the array size.
Each binary search cuts the search space in half each time, so the number of steps grows slowly as the list grows.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 7 (2 x log₂(10)) |
| 100 | About 14 (2 x log₂(100)) |
| 1000 | About 20 (2 x log₂(1000)) |
Pattern observation: Operations grow slowly, roughly doubling the input size adds only a few more steps.
Time Complexity: O(log n)
This means the time to count occurrences grows slowly as the list gets bigger, because we use fast searching.
[X] Wrong: "Counting occurrences requires checking every element, so it must be O(n)."
[OK] Correct: Because the array is sorted, we can find the first and last positions quickly using binary search, avoiding checking every element.
Knowing how to use binary search to count occurrences shows you can use the sorted property to make searching efficient, a skill often valued in interviews.
"What if the array was not sorted? How would the time complexity change?"
Practice
Solution
Step 1: Understand binary search efficiency
Binary search divides the search space in half each time, making it faster than checking every element.Step 2: Compare with linear scan
Linear scan checks each element, taking O(n) time, while binary search takes O(log n) time.Final Answer:
It reduces the time complexity to O(log n) compared to a linear scan. -> Option CQuick Check:
Binary search = O(log n) speed [OK]
- Thinking binary search works on unsorted arrays
- Confusing time complexity with memory usage
- Assuming binary search counts without element checks
Solution
Step 1: Identify return type for count
The function should return an integer representing the count, so return type must be int.Step 2: Check parameter order and types
Common convention is array first, then target element; parameters types must match int array and int target.Final Answer:
int CountOccurrences(int[] arr, int target) -> Option BQuick Check:
Return count as int, array then target [OK]
- Using void return type instead of int
- Swapping parameter order incorrectly
- Returning bool instead of count
int[] arr = {1, 2, 2, 2, 3, 4, 5};
int target = 2;
int count = CountOccurrences(arr, target);
Console.WriteLine(count);
int CountOccurrences(int[] nums, int x) {
int first = Array.BinarySearch(nums, x);
if (first < 0) return 0;
int count = 1;
int left = first - 1;
while (left >= 0 && nums[left] == x) {
count++;
left--;
}
int right = first + 1;
while (right < nums.Length && nums[right] == x) {
count++;
right++;
}
return count;
}Solution
Step 1: Find first occurrence index using BinarySearch
BinarySearch finds one occurrence of 2 at index 2.Step 2: Count occurrences left and right of index 2
Left side: index 1 and 0 checked; index 1 is 2 (count=2), index 0 is 1 (stop). Right side: index 3 is 2 (count=3), index 4 is 3 (stop).Final Answer:
3 -> Option AQuick Check:
Occurrences of 2 = 3 [OK]
- Assuming BinarySearch returns first occurrence always
- Counting only one side neighbors
- Returning 0 if not found without checking neighbors
int CountOccurrences(int[] nums, int target) {
int first = Array.BinarySearch(nums, target);
if (first < 0) return 0;
int count = 1;
int left = first - 1;
while (left > 0 && nums[left] == target) {
count++;
left--;
}
int right = first + 1;
while (right < nums.Length && nums[right] == target) {
count++;
right++;
}
return count;
}Solution
Step 1: Analyze left boundary condition in while loop
The loop checks 'left > 0', so it skips index 0, missing a possible occurrence at start.Step 2: Correct boundary condition to include index 0
Changing condition to 'left >= 0' ensures index 0 is checked for target equality.Final Answer:
The left boundary check should be 'left >= 0' instead of 'left > 0'. -> Option DQuick Check:
Check array start index 0 with '>= 0' [OK]
- Using 'left > 0' misses first element
- Returning -1 instead of 0 when not found
- Starting count at 0 instead of 1
- Using wrong right boundary condition
Solution
Step 1: Use binary search to find first occurrence of target
Modify binary search to find the lowest index where target appears.Step 2: Use binary search to find last occurrence of target
Modify binary search to find the highest index where target appears.Step 3: Calculate count from indices
Count = last occurrence index - first occurrence index + 1.Final Answer:
Find the first and last occurrence indices of the target using binary search, then calculate count as last - first + 1. -> Option AQuick Check:
Count = last - first + 1 using two binary searches [OK]
- Using linear scan after one binary search
- Sorting array again unnecessarily
- Using hash map instead of binary search
Ready to prove it?
Pass the test and this pattern moves unknown
