Bird
Raised Fist0
DSA Rustprogramming~15 mins

First and Last Occurrence of Element in DSA Rust - Deep Dive

Choose your learning style10 modes available
Overview - First and Last Occurrence of Element
What is it?
Finding the first and last occurrence of an element means locating the earliest and latest positions where that element appears in a list or array. This helps us know exactly where an element starts and ends in a sequence. It is useful when elements can repeat multiple times. The goal is to find these positions efficiently without checking every element one by one.
Why it matters
Without knowing the first and last occurrence, we might waste time searching through the entire list repeatedly or miss important information about the element's range. This concept helps in tasks like searching logs, counting frequencies, or slicing parts of data quickly. It makes programs faster and more efficient, especially with large data.
Where it fits
Before this, you should understand arrays or lists and basic searching techniques like linear search. After this, you can learn about binary search and advanced searching algorithms that improve speed. This topic is a stepping stone to mastering efficient data retrieval.
Mental Model
Core Idea
The first and last occurrence of an element mark the boundaries of where that element appears in a sequence.
Think of it like...
Imagine a row of identical books on a shelf. The first occurrence is the first copy you see from the left, and the last occurrence is the last copy you see before different books start.
Array: [2, 3, 3, 3, 5, 7, 7, 8]
Element: 3
Positions: 0  1  2  3  4  5  6  7
           |-----|
First occurrence at index 1
Last occurrence at index 3
Build-Up - 7 Steps
1
FoundationUnderstanding Element Positions
šŸ¤”
Concept: Learn what it means for an element to have positions in a list.
An array is a list of items stored in order. Each item has an index starting from 0. For example, in [5, 10, 15], 5 is at index 0, 10 at index 1, and 15 at index 2. When an element appears multiple times, it has multiple positions.
Result
You can identify where each element is located by its index.
Knowing that elements have fixed positions helps us target specific occurrences instead of searching blindly.
2
FoundationLinear Search for Occurrences
šŸ¤”
Concept: Use simple scanning to find where an element appears.
Go through the array from start to end. When you find the element, note its index. For first occurrence, stop at the first match. For last occurrence, keep updating the index until the end.
Result
You get the first and last positions by checking every element.
Linear search is simple but can be slow for large arrays because it checks every item.
3
IntermediateBinary Search Basics
šŸ¤”Before reading on: Do you think binary search can find the first occurrence directly or just any occurrence? Commit to your answer.
Concept: Binary search quickly finds an element in a sorted array by dividing the search space in half repeatedly.
Start with the whole array. Check the middle element. If it matches, you found an occurrence. If the target is smaller, search the left half; if larger, search the right half. Repeat until found or no space left.
Result
You find one occurrence of the element faster than linear search.
Binary search reduces search time from checking all elements to just a few steps, but it may not find the first or last occurrence directly.
4
IntermediateModified Binary Search for First Occurrence
šŸ¤”Before reading on: Will checking only the middle element be enough to find the first occurrence? Commit to your answer.
Concept: Adjust binary search to continue searching left even after finding the element to find the earliest position.
When you find the element at mid, record it but continue searching the left half to see if it appears earlier. Stop when no earlier occurrence is found.
Result
You get the index of the first occurrence efficiently.
Modifying binary search to look left after a match ensures you find the earliest position, not just any match.
5
IntermediateModified Binary Search for Last Occurrence
šŸ¤”Before reading on: Should the search continue to the right or left after finding the element to get the last occurrence? Commit to your answer.
Concept: Similar to first occurrence, but continue searching right after finding the element to find the latest position.
When the element is found at mid, record it and search the right half to find if it appears later. Stop when no later occurrence is found.
Result
You get the index of the last occurrence efficiently.
Searching right after a match ensures you find the last occurrence, completing the range of the element.
6
AdvancedRust Implementation with Binary Search
šŸ¤”Before reading on: Do you think Rust's standard library binary_search can directly give first and last occurrences? Commit to your answer.
Concept: Implement first and last occurrence search in Rust using custom binary search logic.
Use Rust's slice binary_search to find any occurrence. Then use loops with adjusted binary search to find first and last occurrences. Handle cases where element is not found by returning None.
Result
Efficient Rust code that returns Option<(usize, usize)> for first and last positions.
Combining Rust's built-in methods with custom logic leverages safety and speed for practical searching.
7
ExpertHandling Edge Cases and Performance
šŸ¤”Before reading on: Do you think empty arrays or arrays without the element require special handling? Commit to your answer.
Concept: Consider empty arrays, arrays with one element, and elements not present. Also analyze time complexity.
Check if array is empty before searching. If element not found, return None. Binary search runs in O(log n), much faster than linear O(n). For very large data, this difference is critical.
Result
Robust code that handles all cases and performs well on large inputs.
Anticipating edge cases prevents runtime errors and ensures reliable software.
Under the Hood
Binary search works by repeatedly dividing the search interval in half. It compares the target with the middle element and decides which half to keep searching. For first and last occurrences, after finding a match, it continues searching left or right to find boundaries. This avoids scanning the entire array and reduces time complexity from linear to logarithmic.
Why designed this way?
Binary search was designed for sorted data to speed up search operations. The modification to find first and last occurrences addresses the limitation of standard binary search returning any match, which is insufficient when duplicates exist. This design balances speed and accuracy.
Full array
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ 2 │ 3 │ 3 │ 3 │ 5 │ 7 │ 7 │ 8 │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Search steps:
[Start] low=0, high=7
Check mid=3 (value=3) -> match
For first occurrence: move high=mid-1=2
Check mid=1 (value=3) -> match
Move high=mid-1=0
Check mid=0 (value=2) -> less than target
Move low=mid+1=1
No more left side, first occurrence at index 1

For last occurrence: after first match at 3,
move low=mid+1=4
Check mid=5 (value=7) -> greater than target
Move high=mid-1=4
Check mid=4 (value=5) -> greater than target
Move high=mid-1=3
No more right side, last occurrence at index 3
Myth Busters - 4 Common Misconceptions
Quick: Does binary search always find the first occurrence of an element? Commit yes or no.
Common Belief:Binary search always returns the first occurrence of the element in a sorted array.
Tap to reveal reality
Reality:Standard binary search returns any occurrence, not necessarily the first or last.
Why it matters:Assuming it returns the first occurrence can cause bugs when duplicates exist, leading to incorrect indexing or slicing.
Quick: Is linear search always slower than binary search? Commit yes or no.
Common Belief:Linear search is always slower than binary search for finding occurrences.
Tap to reveal reality
Reality:Linear search can be faster for very small or unsorted arrays where binary search is not applicable.
Why it matters:Blindly using binary search on unsorted data leads to wrong results or errors.
Quick: Can you find first and last occurrences without sorting the array? Commit yes or no.
Common Belief:You can find first and last occurrences efficiently without sorting the array.
Tap to reveal reality
Reality:Without sorting, you must scan the entire array (linear search), which is less efficient.
Why it matters:Trying to use binary search on unsorted data causes incorrect results.
Quick: Does the first occurrence always come before the last occurrence? Commit yes or no.
Common Belief:The first occurrence index is always less than or equal to the last occurrence index.
Tap to reveal reality
Reality:This is true by definition; the first occurrence cannot come after the last occurrence.
Why it matters:Understanding this prevents logic errors when validating results or writing conditions.
Expert Zone
1
Binary search for first and last occurrence requires careful boundary updates to avoid infinite loops or missing edge cases.
2
Rust's Option type elegantly handles cases where the element is not found, avoiding null pointer errors common in other languages.
3
In some cases, using built-in methods like slice::binary_search can simplify code but require additional steps to find exact boundaries.
When NOT to use
Do not use binary search for first and last occurrence on unsorted arrays; use linear search instead. For very small arrays, linear search might be simpler and faster. If data changes frequently, maintaining sorted order for binary search may be costly; consider hash maps for frequency queries.
Production Patterns
In real systems, first and last occurrence searches appear in text processing (finding word ranges), database indexing (range queries), and event logs (time intervals). Efficient implementations use binary search combined with caching or indexing structures for repeated queries.
Connections
Binary Search
Builds-on
Understanding first and last occurrence deepens knowledge of binary search by showing how to adapt it for range queries, a common real-world need.
Hash Maps
Alternative approach
Hash maps can quickly count occurrences but do not provide ordered positions, highlighting the unique value of binary search for positional queries.
Event Time Ranges in Scheduling
Application domain
Finding first and last occurrences is like finding start and end times of events, showing how algorithms support practical scheduling and timeline analysis.
Common Pitfalls
#1Using standard binary search result as first occurrence without adjustment.
Wrong approach:let pos = arr.binary_search(&target).unwrap(); // assumes pos is first occurrence
Correct approach:let first = find_first_occurrence(&arr, target); // custom function to find first occurrence
Root cause:Misunderstanding that binary_search returns any match, not necessarily the first.
#2Applying binary search on unsorted array.
Wrong approach:let pos = arr.binary_search(&target); // arr is unsorted
Correct approach:Use linear search or sort array before binary search.
Root cause:Not ensuring precondition of sorted data for binary search.
#3Not handling empty array or element not found cases.
Wrong approach:let pos = arr.binary_search(&target).unwrap(); // panics if not found
Correct approach:match arr.binary_search(&target) { Ok(pos) => pos, Err(_) => return None }
Root cause:Ignoring possibility of no match causing runtime errors.
Key Takeaways
First and last occurrences mark the start and end positions of an element in a sequence, crucial for range queries.
Linear search is simple but inefficient for large sorted arrays; binary search improves speed to logarithmic time.
Modified binary search continues searching left or right after a match to find exact boundaries, not just any occurrence.
Rust's safe types and built-in methods help implement these searches robustly and efficiently.
Understanding edge cases and data conditions prevents common bugs and ensures reliable, fast searching.

Practice

(1/5)
1. What does the "First and Last Occurrence of Element" problem ask you to find in a list?
easy
A. The first and last positions where a given element appears
B. The sum of all elements in the list
C. The maximum and minimum values in the list
D. The number of unique elements in the list

Solution

  1. Step 1: Understand the problem statement

    The problem asks to find the first and last positions of a specific element in a list.
  2. Step 2: Identify what is required

    We need to locate the earliest and latest index where the element appears.
  3. Final Answer:

    The first and last positions where a given element appears -> Option A
  4. Quick Check:

    Positions = first and last occurrence [OK]
Hint: Look for earliest and latest index of element [OK]
Common Mistakes:
  • Confusing with sum or count of elements
  • Looking for max/min values instead
  • Ignoring the order of occurrences
2. Which Rust code snippet correctly finds the first occurrence index of element target in vector v?
easy
A. v.iter().position(|&x| x == target)
B. v.iter().find(|&&x| x == target)
C. v.iter().filter(|&&x| x == target).count()
D. v.iter().last().position(|&x| x == target)

Solution

  1. Step 1: Understand Rust iterator methods

    The position method returns the index of the first element matching the condition.
  2. Step 2: Check each option

    v.iter().position(|&x| x == target) uses position correctly to find the first occurrence index. v.iter().find(|&&x| x == target) returns an Option<&T>, not index. v.iter().filter(|&&x| x == target).count() counts matches, not index. v.iter().last().position(|&x| x == target) is invalid because last() returns an element, not an iterator.
  3. Final Answer:

    v.iter().position(|&x| x == target) -> Option A
  4. Quick Check:

    position() returns first index [OK]
Hint: Use .position() to get first index [OK]
Common Mistakes:
  • Using find() which returns element, not index
  • Using count() which returns number of matches
  • Trying to call position() after last() which is invalid
3. What is the output of this Rust code?
let v = vec![2, 3, 5, 3, 7];
let target = 3;
let first = v.iter().position(|&x| x == target);
let last = v.iter().rposition(|&x| x == target);
println!("[{:?}, {:?}]", first, last);
medium
A. [Some(2), Some(3)]
B. [Some(1), Some(4)]
C. [None, None]
D. [Some(1), Some(3)]

Solution

  1. Step 1: Find first occurrence of 3 in vector

    Vector is [2, 3, 5, 3, 7]. The first 3 is at index 1.
  2. Step 2: Find last occurrence of 3 in vector

    The last 3 is at index 3.
  3. Final Answer:

    [Some(1), Some(3)] -> Option D
  4. Quick Check:

    First = 1, Last = 3 [OK]
Hint: Use position() and rposition() for first and last [OK]
Common Mistakes:
  • Confusing indices of first and last occurrences
  • Using wrong iterator methods
  • Forgetting that indices start at 0
4. Identify the error in this Rust code that tries to find the last occurrence of target in vector v:
let last = v.iter().position(|&x| x == target).unwrap();
println!("{}", last);
medium
A. unwrap() causes panic if element not found
B. v.iter() cannot be used with position()
C. Using position() finds first, not last occurrence
D. Missing semicolon after unwrap()

Solution

  1. Step 1: Understand what position() returns

    position() returns the index of the first element matching the condition, not the last.
  2. Step 2: Identify correct method for last occurrence

    To find the last occurrence, rposition() should be used instead of position().
  3. Final Answer:

    Using position() finds first, not last occurrence -> Option C
  4. Quick Check:

    position() = first occurrence, not last [OK]
Hint: Use rposition() for last occurrence, not position() [OK]
Common Mistakes:
  • Using position() for last occurrence
  • Ignoring unwrap() panic possibility
  • Thinking iter() can't use position()
5. Given a sorted vector v with possible duplicates, which approach efficiently finds the first and last occurrence of target using binary search in Rust?
hard
A. Use find() method twice with different closures
B. Use two binary searches: one for first occurrence, one for last occurrence
C. Use a single linear scan from start to end
D. Use position() and rposition() on the entire vector

Solution

  1. Step 1: Understand the vector is sorted with duplicates

    Binary search can be used to find positions efficiently in sorted data.
  2. Step 2: Use two binary searches for first and last occurrence

    One binary search finds the first index where target appears, another finds the last index.
  3. Final Answer:

    Use two binary searches: one for first occurrence, one for last occurrence -> Option B
  4. Quick Check:

    Binary search twice for first and last [OK]
Hint: Binary search twice for first and last occurrence [OK]
Common Mistakes:
  • Using linear scan on large sorted vector
  • Using position() which is linear time
  • Trying to find both occurrences in one binary search
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