In-Place Removal of Duplicates Exceeding Two Occurrences in Sorted Arrays
When processing sorted arrays where elements may appear multiple times, enforcing a maximum occurrence limit requires a two-pointer technique. The objective is to compact the sequence so that no value repeats more than twicee, achieving this modification within the original memory bounds with out auxiliary storage.
The core strategy utilizes a read pointer to traverse the dataset and a write pointer to track the boundary of the valid segment. Because the input is pre-sorted, identical values are guaranteed to be adjacent. By comparing the current reading element against the element positioned two steps behind the write pointer, we can determine whether a third consecutive occurence has been reached. If the condition holds, the current element is skipped; otherwise, it advances the write boundary and records the value.
Below is a Go implementation demonstrating this optimized approach:
func filterDuplicateOccurrences(nums []int) int {
if len(nums) <= 2 {
return len(nums)
}
targetPos := 1
for scanPos := 2; scanPos < len(nums); scanPos++ {
if nums[scanPos] != nums[targetPos-2] {
targetPos++
nums[targetPos] = nums[scanPos]
}
}
return targetPos + 1
}
Algorithm Breakdown:
- Initialization: The
targetPosmarker begins at1because the first two positions are automatically preserved. - Traversal Loop: The
scanPosvariable scans forward starting from the third element. At each step, it compares againstnums[targetPos-2]. - Deduplication Logic: If the current value matches the element two slots prior, it indicates a duplicate exceeding the allowed threshold, triggering a silent skip. Otherwise, the marker increments, and the value is committed to the front portion of the slice.
- Result Calculation: Since indices are zero-based, adding one to the final marker position yields the exact count of retained elements.
Complexity Analysis:
- Time Complexity: O(N), where N represents the total number of items. Each component traverses the structure exactly once.
- Space Complexity: O(1), as all operations occur directly on the provided data structure using fixed integer variables.
Execution Walkthrough:
Given an initial sequence [0, 0, 1, 1, 1, 1, 2, 3, 3]:
- Indices
0and1remain untouched (0,0). - Processing index
2(1): Compares withnums[0](0). Values differ, sotargetPosadvances to2and stores1. - Processing index
3(1): Compares withnums[1](0). Values differ, advances to3, stores1. Current valid prefix:[0, 0, 1, 1]. - Processing index
4(1): Compares withnums[2](1). Values match third occurrence. Skipped. - Processing index
5(1): Same check againstnums[3](1). Skipped. - Processing index
6(2): Compares withnums[3](1). Differs, advances to4, stores2. - Final valid prefix compacted to
[0, 0, 1, 1, 2, 3, 3]. Function returns length7.