Count Occurrences of Element in Sorted Array in DSA Go - Time & Space Complexity
We want to know how fast we can 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.
func countOccurrences(arr []int, target int) int {
left := binarySearch(arr, target, true)
if left == -1 {
return 0
}
right := binarySearch(arr, target, false)
return right - left + 1
}
func binarySearch(arr []int, target int, findFirst bool) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := low + (high-low)/2
if arr[mid] == target {
result = mid
if findFirst {
high = mid - 1
} else {
low = mid + 1
}
} else if arr[mid] < target {
low = mid + 1
} else {
high = mid - 1
}
}
return result
}
This code finds the first and last position of the target using binary search, then counts how many times it appears.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The binary search loop inside
binarySearchruns repeatedly. - How many times: Each binary search runs about log2(n) times, where n is the array size.
- We do two binary searches: one to find the first occurrence, one for the last.
As the list gets bigger, the number of steps grows slowly, not directly with the size.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 2 x 4 = 8 steps |
| 100 | About 2 x 7 = 14 steps |
| 1000 | About 2 x 10 = 20 steps |
Pattern observation: Doubling the input size adds only a few more steps because binary search cuts the search space in half each time.
Time Complexity: O(log n)
This means the time to count occurrences grows slowly as the list grows, making it very efficient.
[X] Wrong: "Counting occurrences requires checking every element, so it must be O(n)."
[OK] Correct: Because the array is sorted, we can use binary search to jump directly to the target's positions without checking all elements.
Understanding how to use binary search to count occurrences shows you can use smart searching techniques, a skill valued in many coding challenges.
"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 linear search.Step 2: Apply to counting occurrences
By finding the first and last positions of the element, we can count occurrences efficiently.Final Answer:
It reduces the search time to logarithmic complexity. -> Option CQuick Check:
Binary search = O(log n) time [OK]
- Thinking binary search sorts the array
- Using linear search for counting in sorted array
- Assuming binary search works on unsorted arrays
Solution
Step 1: Check function signature syntax
In Go, slices are declared as []int, and return type int is correct for count.Step 2: Validate return statement matches return type
Returning 0 as int matches the return type int.Final Answer:
func countOccurrences(arr []int, target int) int { return 0 } -> Option AQuick Check:
Correct Go function syntax [OK]
- Using array syntax int[] instead of []int
- Mismatching return type and return value
- Omitting return type in function signature
func countOccurrences(arr []int, target int) int {
left := 0
right := len(arr) - 1
first := -1
for left <= right {
mid := (left + right) / 2
if arr[mid] == target {
first = mid
right = mid - 1
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
if first == -1 {
return 0
}
left = 0
right = len(arr) - 1
last := -1
for left <= right {
mid := (left + right) / 2
if arr[mid] == target {
last = mid
left = mid + 1
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return last - first + 1
}
func main() {
arr := []int{1, 2, 2, 2, 3, 4, 5}
count := countOccurrences(arr, 2)
fmt.Println(count)
}Solution
Step 1: Find first occurrence of 2
Binary search finds first index of 2 at position 1.Step 2: Find last occurrence of 2
Binary search finds last index of 2 at position 3.Step 3: Calculate count
Count = last - first + 1 = 3 - 1 + 1 = 3.Final Answer:
3 -> Option BQuick Check:
Occurrences of 2 = 3 [OK]
- Returning index instead of count
- Not updating left/right correctly in binary search
- Confusing first and last occurrence indices
func countOccurrences(arr []int, target int) int {
left, right := 0, len(arr)-1
count := 0
for left <= right {
mid := (left + right) / 2
if arr[mid] == target {
count++
break
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return count
}Solution
Step 1: Analyze loop behavior
The loop breaks after finding one occurrence, so count increments only once.Step 2: Understand counting logic
Counting all occurrences requires searching for first and last positions, not just one match.Final Answer:
It counts only one occurrence, not all. -> Option AQuick Check:
Loop breaks early, count = 1 [OK]
- Using break instead of continuing search
- Not searching for first and last indices
- Assuming one match equals total count
Solution
Step 1: Consider efficiency for multiple targets
Binary search per target is O(k log n) for k targets, which can be costly.Step 2: Use hash map after one scan
A single linear scan builds a map of counts for all elements in O(n), allowing O(1) lookup per target.Step 3: Compare approaches
Hash map approach is more efficient for multiple queries than repeated binary searches.Final Answer:
Use a hash map to store counts after one full scan. -> Option DQuick Check:
Hash map = efficient multiple counts [OK]
- Repeating binary search for each target
- Sorting array multiple times unnecessarily
- Ignoring hash map for frequency counting
Ready to prove it?
Pass the test and this pattern moves unknown
