import Foundation
/// Utility type for finding distances between values in collections.
enum ArrayDistance {
/// Finds the minimum distance between two target values in an array.
///
/// - Parameters:
/// - numbers: The array to search.
/// - target1: The first target value.
/// - target2: The second target value.
///
/// - Returns:
/// The minimum distance between the target values,
/// or `nil` if no valid pair exists.
///
/// - Complexity:
/// - Time: O(n)
/// - Space: O(1)
static func findMinimumDistance(
in numbers: [Int],
between target1: Int,
and target2: Int
) -> Int? {
// Special case: both targets are the same value.
if target1 == target2 {
return findMinimumDistanceBetweenDuplicates(
in: numbers,
target: target1
)
}
var lastSeenIndex: Int?
var minimumDistance: Int?
for (currentIndex, currentValue) in numbers.enumerated() {
// Ignore values that are not targets.
guard currentValue == target1 || currentValue == target2 else {
continue
}
/*
If we previously encountered one target
and the current value is the other target,
update the minimum distance.
*/
if let previousIndex = lastSeenIndex,
currentValue != numbers[previousIndex] {
let distance = currentIndex - previousIndex
minimumDistance = minimumDistance.map {
min($0, distance)
} ?? distance
}
// Remember the most recent occurrence.
lastSeenIndex = currentIndex
}
return minimumDistance
}
/// Finds the minimum distance between consecutive occurrences
/// of the same value.
///
/// - Parameters:
/// - numbers: The array to search.
/// - target: The target value.
///
/// - Returns:
/// The minimum distance between occurrences,
/// or `nil` if fewer than two occurrences exist.
private static func findMinimumDistanceBetweenDuplicates(
in numbers: [Int],
target: Int
) -> Int? {
var previousIndex: Int?
var minimumDistance: Int?
for (currentIndex, currentValue) in numbers.enumerated() {
guard currentValue == target else {
continue
}
if let previous = previousIndex {
let distance = currentIndex - previous
minimumDistance = minimumDistance.map {
min($0, distance)
} ?? distance
}
previousIndex = currentIndex
}
return minimumDistance
}
}
// Example Usage
let numbers = [2, 3, 7, 3, 3, 4, 8, 8, 8, 11, 9, 1, 3]
if let distance = ArrayDistance.findMinimumDistance(
in: numbers,
between: 3,
and: 8
) {
print("Minimum distance between 3 and 8: \(distance)")
} else {
print("No valid pair found.")
}
/*
run:
Minimum distance between 3 and 8: 2
*/