力扣 352. 将数据流变为多个不相交区间

该博客介绍了一种利用有序集合(TreeMap)处理数据流中区间操作的方法。首先,有序集合用于存储区间,以左边界为键,右边界为值。当插入新数时,根据新数与最近的左右区间的关系进行判断,可能的情况包括区间不变、扩大、合并等。最终,有序集合能有效地更新并返回当前的所有区间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:https://leetcode-cn.com/problems/data-stream-as-disjoint-intervals/

大致题意:
给定一组操作,第一个是分割区间初始化,接下来可能是像当前的分割区间中插入一个数(插入可能导致已有区间的变化),也可能是输出当前的分割区间

思路

当初始化后,插入单个数可以理解为插入单个长度为 1 的区间,但是若新插入的区间与已有的区间相邻,那么就需要进行区间合并,当然新插入的区间有可能在已有的区间范围内,这样也就不会生成新的分割区间。
那么,新插入的数对已有区间的影响可能为:

  • 插入一个新区间
  • 导致一个区间的扩大,而区间扩大后有可能与另一个区间相邻,因而也有可能导致区间合并
  • 没有影响

假设:新插入的数 val 左边最近的区间为 [l0, r0](这里保证 l0 <= val),右边最近的区间为[l1, r1](这里保证 l1 > val),那么有以下情况:

  1. l0 <= val <= r0,区间不变化
  2. r0 + 1 = val,左区间向右扩大一位
  3. l1 - 1 = val,右区间向左扩大一位
  4. ro + 1 = l1 - 1 = val,左右两区间合并
  5. val > r0 且 val < l1,区间无变化

那么每次插入 val 后,就可以通过判断它与左右区间的关系来进行相应的操作

有序集合

于是可以使用有序集合来保存当前有的区间:将区间左边界作为 key,右边界作为 value

有序集合也可以查找小于某个数中最大的 key 对应 key-value 对 和 大于某个数中最小的 key 对应 key-value 对,也就是刚刚提到的左区间和右区间

代码:

public class SummaryRanges {
    private TreeMap<Integer, Integer> intervals;

    public SummaryRanges() {
        intervals = new TreeMap<>();
    }

    public void addNum(int val) {
        // 找 最大的 左边界小于等于 val 的区间
        Map.Entry<Integer, Integer> intervals0 = intervals.floorEntry(val);
        // 找 最小的 左边界大于 val 的区间
        Map.Entry<Integer, Integer> intervals1 = intervals.ceilingEntry(val + 1);
        // 情况一
        if (intervals0 != null && intervals0.getKey() <= val && intervals0.getValue() >= val) {
            return;
        }
        else {
            boolean leftSide = intervals0 != null && intervals0.getValue() + 1 == val;
            boolean rightSide = intervals1 != null && intervals1.getKey() - 1 == val;
            // 情况四
            if (leftSide && rightSide) {
                intervals.put(intervals0.getKey(), intervals1.getValue());
                intervals.remove(intervals1.getKey());
            }
            // 情况二
            else if (leftSide) {
                intervals.put(intervals0.getKey(), val);
            }
            // 情况三
            else if (rightSide) {
                intervals.put(val, intervals1.getValue());
                intervals.remove(intervals1.getKey());
            }
            // 情况五
            else {
                intervals.put(val, val);
            }
        }
    }

    public int[][] getIntervals() {
        int n = intervals.size();
        int[][] ans = new int[n][2];
        int idx = 0;
        for (Map.Entry<Integer, Integer> entry : intervals.entrySet()) {
            ans[idx][0] = entry.getKey();
            ans[idx++][1] = entry.getValue();
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值