LeetCode刷题笔记 352区间合并

区间模拟

题目

给你一个由非负整数 a1, a2, …, an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表。

实现 SummaryRanges 类:

SummaryRanges() 使用一个空数据流初始化对象。
void addNum(int val) 向数据流中加入整数 val 。
int[][] getIntervals() 以不相交区间 [starti, endi] 的列表形式返回对数据流中整数的总结。
示例

输入:
["SummaryRanges", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals"]
[[], [1], [], [3], [], [7], [], [2], [], [6], []]
输出:
[null, null, [[1, 1]], null, [[1, 1], [3, 3]], null, [[1, 1], [3, 3], [7, 7]], null, [[1, 3], [7, 7]], null, [[1, 3], [6, 7]]]

解释:
SummaryRanges summaryRanges = new SummaryRanges();
summaryRanges.addNum(1);      // arr = [1]
summaryRanges.getIntervals(); // 返回 [[1, 1]]
summaryRanges.addNum(3);      // arr = [1, 3]
summaryRanges.getIntervals(); // 返回 [[1, 1], [3, 3]]
summaryRanges.addNum(7);      // arr = [1, 3, 7]
summaryRanges.getIntervals(); // 返回 [[1, 1], [3, 3], [7, 7]]
summaryRanges.addNum(2);      // arr = [1, 2, 3, 7]
summaryRanges.getIntervals(); // 返回 [[1, 3], [7, 7]]
summaryRanges.addNum(6);      // arr = [1, 2, 3, 6, 7]
summaryRanges.getIntervals(); // 返回 [[1, 3], [6, 7]]

分析

需要通过数字来生成区间,且数字并不是按照大小顺序出现。因此,需要用一个动态结构来维护这样的区间操作。为了方便数据加入,可以通过并查集或者其他方式尽快定位可以加速。

方法一

简单的表记录法,用数组来记录每个值。
时间复杂度O( C),空间复杂度O( C),C = 10001。

class SummaryRanges {

    public boolean[] ifnums;
    public SummaryRanges() {
        ifnums = new boolean[10001];
    }
    
    public void addNum(int value) {
        ifnums[value] = true;
    }
    
    public int[][] getIntervals() {
        List<int[]> list = new ArrayList();
        int start = -1, end = -1;
        for(int i = 0; i < 10000; ++ i){
            if(ifnums[i]){
                if(start == -1){
                    start = i;
                    end = i;
                }
                else{
                    end = i;
                }
            }
            else{
                if(start != -1){
                    list.add( new int[]{start,end});
                    start = -1;
                    end = -1;
                }
            }
        }
        int size = list.size();
        return list.toArray(new int[size][2]);
    }
}

方法二

并查集来加速搜索过程,优化右边界的搜索。

class SummaryRanges {
    public int[] father = new int[10001];
    public SummaryRanges() {
        Arrays.fill(father,-1);
    }
    public void union(int x, int y){
        if(x >=0 && x <=10000 && father[x] != -1 && father[y] != -1){
            int fx = find(x);
            int fy = find(y);
            if( fx != fy){
               father[fx] = fy; 
            }
        }
    }

    public int find(int x){
        while(x != father[x]){
            x = father[x];
        }
        return x;
    }

    public void addNum(int val) {
        if(father[val] == -1){
            father[val] = val;
            union(val, val + 1);
            union(val - 1, val);
        }
    }
    
    public int[][] getIntervals() {
        List<int[]> temp = new ArrayList<>();
        for(int i = 0; i < 10000;){
            if(father[i] != -1){
                int s = i;
                int e = find(i);
                temp.add(new int[]{s,e});
                i = e + 1;
            }
            else{
                ++ i;
            }
        }
        return temp.toArray(new int[temp.size()][2]);
    }
}
 

时间复杂度O( C),C为10001,但存在路径压缩,因此会小一些。
空间复杂度O( C),C为temp链表大小。

方法三

并查集优化了右边界的查找,但是左边界仍需要依次遍历,因此可以通过set的方式来记录存在的左边界。

class SummaryRanges {
    public int[] father = new int[10001];
    public Set<Integer> set;
    public SummaryRanges() {
        Arrays.fill(father,-1);
        set = new TreeSet<>();
    }
    public void union(int x, int y){
        if(x >=0 && x <=10000 && father[x] != -1 && father[y] != -1){
            int fx = find(x);
            int fy = find(y);
            if( fx != fy){
               father[fx] = fy; 
               set.remove(y);
            }
        }
    }

    public int find(int x){
        while(x != father[x]){
            x = father[x];
        }
        return x;
    }

    public void addNum(int val) {
        if(father[val] == -1){
            set.add(val);
            father[val] = val;
            union(val, val + 1);
            union(val - 1, val);
        }
    }
    
    public int[][] getIntervals() {
        List<int[]> temp = new ArrayList<>();
        for(int start: set){
            int end = find(start);
            temp.add(new int[]{start,end});
        }
        return temp.toArray(new int[temp.size()][2]);
    }
}

时间复杂度O(logk)k为左边界数量
空间复杂度O( C ) C为Treeset的大小

方法四

二分法,具体思路就是将左边的遍历过程改为通过二分搜索减少遍历数量,时间复杂度为O(logN)N为10001。相较于并查集慢,因此,不采用该种方式。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值