declare(strict_types=1);
/**
* Provides utility methods for working with arrays.
*/
final class ArrayDistance
{
/**
* Prevent instantiation of this utility class.
*/
private function __construct()
{
}
/**
* Finds the minimum distance between two target values in an array.
*
* Example:
* [2, 3, 7, 3, 3, 4, 8, 8, 8, 11, 9, 1, 3]
*
* Targets:
* 3 and 8
*
* Result:
* 2
*
* @param int[] $numbers Input array.
* @param int $target1 First target value.
* @param int $target2 Second target value.
*
* @return int Minimum distance between the targets,
* or -1 if no valid pair exists.
*/
public static function findMinimumDistance(
array $numbers,
int $target1,
int $target2
): int {
// Special case: both targets are the same value.
if ($target1 === $target2) {
return self::findMinimumDistanceBetweenDuplicates(
$numbers,
$target1
);
}
$lastSeenIndex = -1;
$minimumDistance = PHP_INT_MAX;
foreach ($numbers as $currentIndex => $currentValue) {
// Skip irrelevant values.
if ($currentValue !== $target1 &&
$currentValue !== $target2) {
continue;
}
/*
* If we've previously seen one target value and
* the current value is the other target value,
* update the minimum distance.
*/
if ($lastSeenIndex >= 0 &&
$currentValue !== $numbers[$lastSeenIndex]) {
$distance = $currentIndex - $lastSeenIndex;
$minimumDistance = min(
$minimumDistance,
$distance
);
}
// Remember the most recent occurrence.
$lastSeenIndex = $currentIndex;
}
return $minimumDistance === PHP_INT_MAX
? -1
: $minimumDistance;
}
/**
* Finds the minimum distance between consecutive occurrences
* of the same value.
*
* @param int[] $numbers Input array.
* @param int $target Target value.
*
* @return int Minimum distance, or -1 if the value occurs
* fewer than two times.
*/
private static function findMinimumDistanceBetweenDuplicates(
array $numbers,
int $target
): int {
$previousIndex = -1;
$minimumDistance = PHP_INT_MAX;
foreach ($numbers as $currentIndex => $currentValue) {
if ($currentValue !== $target) {
continue;
}
if ($previousIndex >= 0) {
$distance = $currentIndex - $previousIndex;
$minimumDistance = min(
$minimumDistance,
$distance
);
}
$previousIndex = $currentIndex;
}
return $minimumDistance === PHP_INT_MAX
? -1
: $minimumDistance;
}
}
/*
* Example usage
*/
$numbers = [2, 3, 7, 3, 3, 4, 8, 8, 8, 11, 9, 1, 3];
$result = ArrayDistance::findMinimumDistance($numbers, 3, 8);
if ($result >= 0) {
echo "Minimum distance between 3 and 8: {$result}" . PHP_EOL;
} else {
echo "No valid pair found." . PHP_EOL;
}
/*
run:
Minimum distance between 3 and 8: 2
*/