合并多段数字区间的解决方案

场景:
给定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、区间必须有下限(嗯),可以无上限。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值