A range intersection algorithm better than O(n)?

前端 未结 9 753
悲&欢浪女
悲&欢浪女 2020-12-04 18:27

Range intersection is a simple, but non-trivial problem.

Its has been answered twice already:

  • Find number range intersection
  • Comparing date ra
9条回答
  •  误落风尘
    2020-12-04 19:07

    When I had this problem, I used a sorted array of ranges and a binary search to look for intersections. This is (I believe) O(log n) performance, with a little bit of overhead to deal with overlapping ranges.

    The answer to your question is, I think, derivable from the code below, but stopping short of the insertion. I present the entire code to avoid confusion by the differing context - I needed to insert a range of Unicode codepoints into a list of codepoint ranges.

    -- EDIT --

    Adapting the code below to determine intersections of multiple ranges involves a trivial forward search from the insertion point until a range is found which no longer intersects.

    -- END EDIT --

    The Range class contains:

    final int                               lower;                                  // lower end of range
    final int                               upper;                                  // upper end of range
    
    public int compareTo(Object obj) {
        if(obj==null) { return -1; }
    
        Range                           oth=(Range)obj;
    
        if(loweroth.lower) { return  1; }
        if(upperoth.upper) { return  1; }
        return 0;
        }
    

    Range Insertion:

    public Builder addRange(int fir, int las) {
        if(fir!=-1) { fir&=0x001FFFFF; }
        if(las!=-1) { las&=0x001FFFFF; }
    
        if(codepoints==null || codepoints.length==0) {
            codepoints=new Range[]{new Range(fir,las)};
            }
        else {
            int                         idx=Range.findChar(codepoints,fir);
            int                         ins=(idx<0 ? -(idx+1) : idx);
    
            if(idx<0) {
                if     (ins>0                 && fir==(codepoints[ins-1].upper+1)) { idx=(ins-1); }  // new range adjoins the following range (can't overlap or idx would be >=0)
                else if(ins=(codepoints[ins  ].lower-1)) { idx=ins;     }  // new range overlaps or adjoins the following range
                }
    
            if(idx<0) {
                codepoints=(Range[])Util.arrayInsert(codepoints,ins,new Range(fir,las));
                }
            else {
                boolean                 rmv=false;
    
                for(int xa=(idx+1); xafir || codepoints[idx].upperlas ? codepoints[idx].upper : las));
                    }
                if(rmv) { codepoints=Range.removeNulls(codepoints); }
                }
            }
        return this;
        }
    

    Binary Search:

    static int findChar(Range[] arr, int val) {
        if(arr.length==1) {
            if     (val< arr[0].lower) { return -1; }                             // value too low
            else if(val<=arr[0].upper) { return  0; }                             // value found
            else                       { return -2; }                             // value too high
            }
        else {
            int                             lowidx=0;                               // low index
            int                             hghidx=(arr.length-1);                  // high index
            int                             mididx;                                 // middle index
            Range                           midval;                                 // middle value
    
            while(lowidx<=hghidx) {
                mididx=((lowidx+hghidx)>>>1);
                midval=arr[mididx];
                if     (val< midval.lower) { hghidx=(mididx-1); }                   // value too low
                else if(val<=midval.upper) { return mididx;     }                   // value found
                else                       { lowidx=(mididx+1); }                   // value too high
                }
            return -(lowidx+1);                                                     // value not found.
            }
        }
    

提交回复
热议问题