PHP中如何基于百分位区间数组匹配总分对应的百分位值
PHP高效实现百分位匹配方案
由于你的percentile_bounds数组本身是升序排列的,不需要全量遍历过滤,可以直接用二分查找实现O(logn)时间复杂度的匹配,比原实现的O(n)性能提升明显,同时天然兼容所有边界条件:
<?php // 升序数组中查找第一个大于等于目标值的索引 function binary_search_first_ge(array $arr, int $target): int { $left = 0; $right = count($arr); while ($left < $right) { $mid = (int)(($left + $right) / 2); if ($arr[$mid] >= $target) { $right = $mid; } else { $left = $mid + 1; } } return $left; } // 测试用例 $percentile_bounds = [84, 104, 109, 115, 120, 123, 125, 127, 129, 132, 135, 136, 137,139, 141, 145, 148, 151, 155, 159]; $percentiles = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]; // 示例1:130 => 40 $total_score = 130; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 示例2:153 =>85 $total_score = 153; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 示例3:100 =>0 $total_score = 100; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 示例4:120 =>15 $total_score = 120; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 边界测试:84 =>0 $total_score = 84; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 边界测试:70 =>0 $total_score = 70; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL; // 边界测试:160(超过最大值)=>95 $total_score = 160; $index = binary_search_first_ge($percentile_bounds, $total_score); echo $percentiles[$index == 0 ? 0 : $index - 1] . PHP_EOL;
短数组场景简洁写法
如果你的百分位区间数组长度很小,想要更精简的代码,也可以用逆序遍历提前终止的方案,比原实现少一次array_search遍历:
<?php $percentile_bounds = [84, 104, 109, 115, 120, 123, 125, 127, 129, 132, 135, 136, 137,139, 141, 145, 148, 151, 155, 159]; $percentiles = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]; $total_score = 120; $res = 0; foreach (array_reverse($percentile_bounds, true) as $k => $v) { if ($v < $total_score) { $res = $percentiles[$k]; break; } } echo $res;
内容的提问来源于stack exchange,提问作者My Work
相关产品推荐
相关产品推荐

