企业保险保障时间与合并区间算法应用

56 阅读4分钟

 关于合并区间类题型和实际业务的应用...

01 — 需求说明 统计某个企业的保险保障信息,关键信息包括: 企业维度的已保障天数、剩余保障天数。

       业务领域上分为:保险方案领域、保单领域。保障信息对应保单对接状态为已生效、满期终止状态,不包括:未投保、投保中、投保成功等中间态保单。

       一家企业可同时存在多个方案、对应多个保单。各方案保障时间可能存在保障时间或重叠或不连续的场景;

       筛选出某个企业的保单对接状态为已生效、满期终止关联的方案保障时间可能存在以下场景:

  1. 保障时间不重叠,且无断保情况(周期连续)

    方案1 [2022-02-01 00:00:00, 2022-02-09 23:59:59]

    方案2  [2022-02-10 00:00:00, 2022-03-10 23:59:59]

    方案3 [2022-03-11 00:00:00, 2022-04-10 23:59:59]

  2. 保障时间不重叠,周期不连续

    方案1  [2022-03-27 00:00:00, 2022-03-28 23:59:59]

    方案2 [2022-03-09 00:00:00, 2022-03-16 23:59:59]

    方案3  [2022-02-01 00:00:00, 2022-02-09 23:59:59]

  3. 保障时间重叠

    方案1 [2022-03-16 00:00:00, 2022-03-24 23:59:59]

    方案2 [2022-03-21 00:00:00, 2022-03-30 23:59:59]

    方案3 [2022-02-23 00:00:00, 2022-03-01 23:59:59]

02 — 实现思路 以上三类场景从处理逻辑复杂度,1<2<3。

        场景1: 只需要考虑首尾两个时间点,再通过与当前时间比对来计算天数即可。

        场景2: 存在周期不连续问题,需要先计算出当前时间属于哪个周期,再来计算天数即可。

        场景3: 需要先合并时间区间,再按照场景ii处理即可。

    合并完时间区块
    1.[2022-02-23 00:00:00,2022-03-01 23:59:59]
    2.[2022-03-16 00:00:00,2022-03-30 23:59:59]
    当前时间:2022-03-29 02:53:31 
    已保障天数:21
    剩余保障天数:1
合并时间区间代码:

        力扣地址:

        leetcode.cn/problems/Ss…

public List < List < Long >> merge(List < List < Long >> intervals) {
    if (intervals.size() == 0) {
        return new ArrayList < > ();
    }
    //按左边界按升序排序       
    intervals.sort(new Comparator < List < Long >> () {@
        Override public int compare(List < Long > o1, List < Long > o2) {
            return o1.get(0).compareTo(o2.get(0));
        }
    });
    List < List < Long >> merged = new ArrayList < List < Long >> ();
    for (int i = 0; i < intervals.size(); ++i) {
        Long L = intervals.get(i).get(0), R = intervals.get(i).get(1);
        //如果merged容器为空 或者 merged最后一个区块的右边界小于当前区块左边界      
        //此时为初始状态或无交集,加入新区块        
        if (merged.size() == 0 || merged.get(merged.size() - 1).get(1) < L) {
            merged.add(Arrays.asList(L, R));
        } else {
            //否则 合并区块               
            merged.get(merged.size() - 1).set(1, Math.max(merged.get(merged.size() - 1).get(1), R));
        }
    }
    return merged;
}

计算天数代码:

//计算剩余保障天数
public Long calcuRestInsureDays(Long target, List < List < Long >> blocks) {
    Long res = 0 L;
    for (int i = blocks.size() - 1; i >= 0; i--) {
        //当前时间大于当前区块右边界,至此可以得到剩余保障天数
        if (target > blocks.get(i).get(1)) {
            break;
        }
        if (target >= blocks.get(i).get(0) && target <= blocks.get(i).get(1)) {
            //在某块区间内,可跳出循环
            res = blocks.get(i).get(1) - target + res;
            break;
        } else {
            //endTime + 1ms 便于计算天数 23:59:59算完整一天
            res += blocks.get(i).get(1) + 1 - blocks.get(i).get(0);
        }
    }
    return res / DateUnit.DAY.getMillis();
}


//计算已保障时间-天数
public Long calcuInsuredDays(Long target, List < List < Long >> blocks) {
    Long res = 0 L;
    for (int i = 0; i < blocks.size(); i++) {
        if (target < blocks.get(i).get(0)) {
            break;
        }
        if (target >= blocks.get(i).get(0) && target <= blocks.get(i).get(1)) {
            //在某块区间内,可跳出循环
            //考虑当前时间不管是一天中哪个时间点, 都算作一天 +res+DateUnit.DAY.getMillis()
            res = target - blocks.get(i).get(0) + res + DateUnit.DAY.getMillis();
            break;
        } else {
            //endTime + 1ms 便于计算天数 23:59:59算完整一天
            res += blocks.get(i).get(1) + 1 - blocks.get(i).get(0);
        }
    }
    return res / DateUnit.DAY.getMillis();
}

测试方法:

 @Test
 public void calTimeBlock() {
     Date date1 = DateUtil.beginOfYear(new Date());
     DateTime dateTime = DateUtil.beginOfDay(date1);
     //2022.01.01
     System.out.println(dateTime);
     List < List < Long >> times = new ArrayList < > ();
     List < List < DateTime >> times2 = new ArrayList < > ();
     for (int i = 0; i < 3; i++) {
         int r1 = new Random().nextInt(100);
         int r2 = r1 + new Random().nextInt(10);
         DateTime dateTime1 = DateUtil.offsetDay(date1, r1);
         DateTime dateTime2 = DateUtil.endOfDay(DateUtil.offsetDay(date1, r2));
         times.add(Arrays.asList(dateTime1.getTime(), dateTime2.getTime()));
         times2.add(Arrays.asList(dateTime1, dateTime2));
     }
     System.out.println(times);
     System.out.println(times2);
     List < List < Long >> blocks = merge(times);
     for (List < Long > tmp: blocks) {
         System.out.println(DateTime.of(tmp.get(0)) + " " + DateTime.of(tmp.get(1)));
     }
     //2022-03-29 02:53:31 1648493611000
     long cur = 1648493611000 L;
     System.out.println(calcuInsuredDays(cur, blocks));
     System.out.println(calcuRestInsureDays(cur, blocks));
 }