场景:
给定N个数字区间,允许选择任意个。
目标:返回合并后的区间。
举个栗子:
给定5个区间如下:
ID 区间范围
1 (0,100)
2 [100,200)
3 [200,300)
4 [300,400)
5 (1000,2000]
6 (2000,3000]
7 (3000,+∞)
假设选择的区间为:1、2、4、6、7
则期望返回合并后的区间:
(0,200)
[300,400)
(2000,+∞)
探索出了一个解决方案,欢迎拍砖:
/**
* 合并多段数字区间
* @param array $inputArr 给定的区间ID。 例:
* array(1,2)
* @param array $intervalArr 区间定义,包括区间ID和数值范围,整个区间必须有下限,可以无上限。 例:
* array(
* 1 => array(
* '>' => 0,
* '<=' => 3000,
* ),
* 2 => array(
* '>' => 3000,
* '<=' => 6000,
* ),
* 3 => array(
* '>' => 6000,
* )
* )
* @return array $resultArr 返回合并后的区间数组。 例:
* array(
* array(
* '>' => 0,
* '<=' => 6000
* )
* )
*/
public function mergeDigitalInterVal($inputArr, $intervalArr) {
$lastArr = $curArr = $resultArr = array();
// 对给定的区间ID数组按照ID从小到大排序
sort($inputArr);
// 遍历给定的区间ID
foreach ($inputArr as $key => $input) {
$input = intval($input);
if(!isset($intervalArr[$input])) {
continue;
}
$lastUpperArr = $curLowerArr = $lastLowerArr = $curUpperArr = array();
$curArr = $intervalArr[$input]; // 获取当前区间
if($lastArr) { // 如果存在上个区间
$lastUpperArr = array_slice($lastArr, 1, 1); // 获取上个区间的上限
$curLowerArr = array_slice($curArr, 0, 1); // 获取当前区间的下限
if(array_shift($lastUpperArr) == array_shift($curLowerArr)) { // 上个区间和当前区间可合并
$lastLowerArr = array_slice($lastArr, 0, 1); // 获取上个区间的下限
if(count($curArr) > 1) { // 当前区间有上限
$curUpperArr = array_slice($curArr, 1, 1); // 获取当前区间的上限
$lastArr = $lastLowerArr + $curUpperArr; // 上个区间为合并后新的区间
if(($key+1) == count($inputArr)) { // 已经遍历到最后一个
$resultArr[] = $lastArr;
break;
}
$curArr = array();
continue;
} else { // 当前区间没有上限,说明已经遍历到最后一个
$resultArr[] = $lastLowerArr;
break;
}
} else { // 上个区间和当前区间不可合并
$resultArr[] = $lastArr; // 保存上个区间
if(($key+1) == count($inputArr)) { // 已经遍历到最后一个
$resultArr[] = $curArr; // 保存当前区间并退出循环
break;
}
}
} else if(($key+1) == count($inputArr)) { // 不存在上个区间,且已经遍历到最后一个,直接保存当前区间并退出循环
$resultArr[] = $curArr;
break;
}
$lastArr = $curArr;
$curArr = array();
}
return $resultArr;
}
注意此方法需要满足以下约定:
1、相邻区间端点落在同一点上时,包含端点值本身。
2、区间必须有下限(嗯),可以无上限。