Leetcode——将数据流变为多个不相交区间

1. 将数据流变为多个不相交区间

在这里插入图片描述

(1)模拟

假设当前第一次加入一个值为 val 的元素,那么只有四种情况:

  • (1)数据流中已经被加入了 val - 1 和 val + 1 两个元素,但因为 val 第一次被加入,所以当前数据流的区间列表中,一定存在两个区间,一个以 val - 1 结尾,另一个以 val + 1 开头。那么,加入 val 后,这两个区间就可以被合并为一个区间。
  • (2)数据流中已经被加入了 val - 1,但没有 val + 1。此时,区间列表中一定存在一个区间,以 val - 1 结尾,我们将 val 加入后,只需将该区间的右端点修改为 val 即可。
  • (3)数据流中已经被加入了 val + 1,但没有 val - 1。与第二种情况类似,我们将以 val + 1 为左端点的区间左端点改为 val 即可。
  • (4)数据流中 val - 1 和 val + 1 均未出现过,此时 val 将自己形成一个独立的区间。

为了快速找到以某个值为左端点或右端点的区间,我们可以每次加入一个整数后,都将区间列表排序,以保证可以使用二分法。

注意:

由于前三种情况都需要找到以某个值为左端点或者右端点的区间在区间列表中的位置,

所以我们在代码中封装了一个二分法函数:binarySearch,用于指明要找的是左端点还是右端点 (0左1右)

看看代码:

class SummaryRanges {
    
    
    List<int[]> tempList;
    Set<Integer> numSet;
    public SummaryRanges() {
    
    
        tempList = new ArrayList<>();
        numSet = new HashSet<>();
    }

    public void addNum(int val) {
    
    
        if (numSet.contains(val)) {
    
    
                return;
        }
        numSet.add(val);
        //需要合并 [..., val - 1] 和 [val + 1, ...] 两个区间
        if (numSet.contains(val-1) && numSet.contains(val+1)) {
    
    
            int left = binarySearch(val-1,1);
            int right = binarySearch(val+1,0);
            tempList.get(left)[1] = tempList.get(right)[1];
            tempList.remove(right);
        } else if (numSet.contains(val+1)) {
    
    
        //val + 1 出现过,说明有以 val + 1 为左端点的区间
            int ans = binarySearch(val+1,0);
            tempList.get(ans)[0] = val;
         }else if (numSet.contains(val-1)) {
    
    
        //有以 val - 1 为右端点的区间
            int ans = binarySearch(val-1,1);
            tempList.get(ans)[1] = val;
        } else {
    
    
            // 左右都未出现,val 形成一个独立区间
            tempList.add(new int[]{
    
    val,val});
        }
        Collections.sort(tempList,(o1, o2) -> o1[0]-o2[0]);
    }

    public int[][] getIntervals() {
    
    
        int lenN = tempList.size();
        int[][] ans = new int[lenN][2];
        for(int i = 0; i < lenN; i++) {
    
    
            ans[i] = tempList.get(i);
        }
        return ans;
    }
    
    //pos 指明要找的是左端点还是右端点 0左1右
    public int binarySearch(int target ,int pos){
    
    
        int left = 0, right = tempList.size()-1;
        while (left <= right) {
    
    
            int mid = left + (right - left) / 2;
            int tempVal = tempList.get(mid)[pos];
            if (tempVal == target) {
    
    
                return mid;
            } else if (tempVal < target) {
    
    
                left = mid + 1;
            } else {
    
    
                right = mid - 1;
            }
        }
        return -1;
    }
}
/**
 * Your SummaryRanges object will be instantiated and called as such:
 * SummaryRanges obj = new SummaryRanges();
 * obj.addNum(val);
 * int[][] param_2 = obj.getIntervals();
 */

猜你喜欢

转载自blog.csdn.net/ly0724ok/article/details/120667747