문제

범위를 교차하는 간단하지만,이 아닌 사소한 문제입니다.

그 대답했 이름:

첫 솔루션 O(n)그리고 두 번째는 솔루션을 위한 데이터베이스(보 O(n)의 코스).

가 동일한 문제이지만,대형 n 내가 내에서 데이터베이스입니다.

이 문제의 것과 매우 유사하 저장 2D 점 빠른 검색을 위해 사람들의 내부 사각형 하지만 난 어떻게 보지도.

그래서 어떤 데이터 구조는 것을 저장하는 설정의 범위에,그러한가에서 검색 범위보다 적은 비용 O(n)?(추가 신용해 사용하는 라이브러리를 사용할 수 있습니다 Java)

편집:

하고 싶어 하위 집합의 모든 교차하는 범위,의미를 검색 범위를 수 있는 교차하는 여러 개의 범위를 다룹니다.

하는 방법을 요구 보다는 더 적은 수 O(n)Java:

public class RangeSet {
    ....
    public Set<Range> intersects(Range range);
    ....
}

는 범위는 단지 등을 포함하는 한 쌍의 int 의 시작과 끝입니다.

이것은 불가능한 질문가 솔루션을,저는 그냥 보고 싶은 경우가 있었다 더 표준에/더 간단한 방법으로 그 일의

도움이 되었습니까?

해결책

표준 접근법은 An을 사용하는 것입니다 간격 트리.

컴퓨터 과학에서 간격 트리는 간격을 유지하는 트리 데이터 구조입니다. 구체적으로, 주어진 간격 또는 지점과 겹치는 모든 간격을 효율적으로 찾을 수 있습니다. 예를 들어, 직사각형 뷰포트 내부의 전산화 된 맵의 모든 도로를 찾거나 3 차원 장면 내부의 모든 가시 요소를 찾는 데 종종 윈도우 쿼리에 사용됩니다. 비슷한 데이터 구조는 세그먼트 트리입니다.

사소한 솔루션은 각 간격을 방문하고 주어진 지점 또는 간격을 교차하는지 여부를 테스트하는 것입니다. 여기서 O (n) 시간이 필요합니다. 여기서 n은 컬렉션의 간격 수입니다. 쿼리가 모든 간격을 반환 할 수 있으므로, 예를 들어 쿼리가 컬렉션의 모든 간격을 교차하는 큰 간격 인 경우, 이것은 비대칭 적으로 최적입니다. 그러나 출력에 민감한 알고리즘을 고려하여 런타임이 쿼리에 의해 생성 된 간격 수인 M으로 표현되는 출력에 민감한 알고리즘을 고려하여 더 잘 수행 할 수 있습니다. 간격 트리는 O (log n + m)의 쿼리 시간과 O (n log n)의 초기 생성 시간을 가지고 있으며 메모리 소비를 O (n)로 제한합니다. 생성 후, 간격 트리는 역동적 일 수 있으며, O (log n)의 간격을 효율적으로 삽입하고 삭제할 수 있습니다. 간격의 종말점이 작은 정수 범위 내에있는 경우 (예 : [1, ..., o (n)] 범위에서 (예 : [1, ..., o (n)]) 내에있는 경우, 더 빠른 데이터 구조 [1] 전처리 시간 O (n) 및 쿼리 시간 O (O)가 있습니다. 1+m) 주어진 쿼리 포인트를 포함하는 M 간격을보고합니다.

다른 팁

편집하다:이 솔루션이 어느 정도 또는 적은 것 같습니다 간격 트리. 간격 트리의보다 완전한 구현을 찾을 수 있습니다. 여기.

class TreeNode
{
public:
    long pivot;
    List<Range> leaves;  //Any ranges that intersect the pivot
    TreeNode left;        //Tree nodes that fall to the left of the pivot
    TreeNode right;       //Tree nodes that fall to the right of the pivot
};

prep o (n log n) :

  1. 범위 목록을 만듭니다
  2. 피벗 포인트를 선택하십시오 (아마도 종료 날짜의 정렬 된 목록을 사용하여) ??
  3. 나무를 짓십시오.

검색:

  1. 이진 검색을 사용하여> = testrange.end 인 첫 번째 피벗을 찾으십시오.
  2. 피벗> testrange.start까지 트리를 가로 지르십시오

    2A. 결과에 잎을 추가하십시오.


예시:

범위 :

  • 0 - 2
  • 1 - 2
  • 2 - 3
  • 1 - 4
  • 2 - 4
  • 0 - 5
  • 4 - 5
  • 2 - 6
  • 3 - 7

나무:

                             4
               --------------+------------------
               3             |                 7
               |            1-4                |
               |            2-4                |
               |            0-5                |
               |            4-5                |
      ---------+------                 --------+--------
      2        |    null              6        |       null
 -----+----   2-3                 ----+----   3-7
null  |  null                   null  |  null    
     0-2                             2-6
     1-2

겹치는 범위 :

prep o (n log n) :

  1. 범위의 배열 / 벡터를 만듭니다.
  2. 범위의 끝까지 벡터를 정렬합니다 (범위의 시작으로 정렬하여 타이 브레이크 타이).

검색:

  1. 이진 검색을 사용하여 최종 값> = testrange.start의 첫 번째 범위를 찾으십시오.
  2. 시작> testrange.end를 찾을 때까지 바이너리 검색에서 시작하는 반복자 :

    2A. 현재 범위가 테스트 레인지 내에있는 경우 범위가 결과에 추가하십시오.

이것은 링크 된 질문에서 정확한 문제에 따라 달라집니다. 뚜렷하고 일반적인 부분이없고 검색 된 범위가 여러 범위에 걸쳐있을 수있는 범위입니다. 문제가 동일하다면 정말 쉽습니다. 범위의 배열을 가져 가서 가장 낮은 값으로 정렬하십시오 (겹치지 않기 때문에 상위 값으로 정렬 된 순서도 동일합니다).

이제 대상이 낮은 값 (또는 정확하지 않은 경우 더 작은)과 대상 상위 값 (또는 정확하지 않은 경우 더 큰)에 대한 신경 검색을 만드십시오. 결과 인덱스는 범위입니다. 인덱스 자체의 범위를 wheter를 점검해야하지만 2 개의 수표 일뿐입니다. 전반적인 복잡성 o (log n).

겹치는 범위 :

prep o (n log n) :

  1. 범위의 배열 / 벡터를 만듭니다.
  2. 범위의 끝까지 벡터를 정렬합니다 (범위의 시작으로 정렬하여 타이 브레이크 타이).
  3. ints의 두 번째 벡터를 만드십시오. 이것은 검색을 중지 할 수있는 지점을 나타냅니다.

    int stop[size];
    stop[size-1] = Ranges[size - 1].start;
    for (int i = size - 2; i >= 0; i--)
    {
        stop[i] = min(Ranges[i].start, stop[i+1]);
    }
    

검색:

  1. 이진 검색을 사용하여 최종 값> = testrange.start의 첫 번째 범위를 찾으십시오.
  2. 중지 될 때까지 이진 검색에서 시작하는 반복자 [i]> testrange.end :

    2A. 현재 범위가 테스트 레인지 내에있는 경우 범위가 결과에 추가하십시오.

는 경우 범위를 중복하고 싶어 검색 모든 는 범위 중복(또는 포함)주어진 목표,범위의 솔루션을 위에 나타나지 않는다.

으로 일부 지적했는 경우,(worst-case) 모든 범위하는 일이 교차하는 대상 범위(예를 들어,대상 범위{0..MAXINT}또는 이와 유사한)다음의 물론 그것 O(n)을 반환합 n 범위입니다.

하지만 재미 있고 전형적인 평균/경우,어디에 매우 작은%n 총 범위가 교차하는 대상 범위입니까?전화 번호 교차하는"m"--는 경우에,당신은 수도 생각 할 수 있을 뿐만 아니라 O(m).경 n=10^9m=10,그들에게 또는 휴식의 차이입니다.

을 고려의 간단한 경우 텍스트 문서가 다양한 지역 표시된 그들의"유형"--아마도 당신을 찾으려면 모든 표시된업 단위는 포함하거나 교정 인접한 범위의 텍스트(예를 들어,단락).HTML,XML,또는 이와 유사한 사람들만의 조상의 텍스트 노드(들)를 포함하는 적어도 일부 문자는 대상의 범위에 있습니다.에서 일반적인 표현으로 부모 포인터에서는 각 노드,그 O(m)--방법보다 더 O(n),특히 때문에 m(에 대한 짧은 또는 동기 대상 범위)단순히 나무 중첩 깊이있는 경향이 있는 것보다 훨씬 낮은 ln(n)기 때문에 큰 XML 문서를 실천에서 얻을 꼬집하지 않 깊다.

흥미로운 경우가 더 열심히:만약 당신의 요소를 형성하지 않는 나무로에서는 XML,그러나 겹칠 수 있습으로 MECS,클릭스,LMNL,그리고 몇 가지 다른 시스템의 차이점은 무엇입니까?당신은 여전히을 찾으려면 모든 지역/"요소는"중복되는 당신의 대상이지만,그들은 그렇게 쉽게 구성되어있다.

에 다른 한편으로는,당신이 할 수 있어야 하기 때문에 아주 잘 표시된 업 범위에 많은 응용 프로그램에서는 가장 많은 훨씬 더 많은 단어,문장 및 단락에서,책상이 있습니다.그래서 심지어가 있기는 하지만의 거대한 숫자는 범위기 전에 시작하는 대상과 거대한 숫자가 종료 후에 그것이 교차하는 것이 매우 작습니다.

나는 생각이 무엇이 원래 질문자에게 얻고 있었고,난 두려워 보지 않았다는 응답되는 주소는 문제입니다.아니면 무엇을 원래의 질문에 대해,다음 나이로 새로운 질문입니다.

SortedSet 인터페이스를 구현하는 클래스가 필요한 것 같습니다. TreeSet은 Core API와 함께 제공되는 구현입니다.

범위를 가장 낮은 값으로 정렬하고 하나는 가장 높은 값으로 정렬 된 세트를 세트해야합니다.

그런 다음 인 메모리 세트를 사용하여 데이터베이스 알고리즘에 해당하는 것을 구현할 수 있습니다.

이것이 실제로 O (n)보다 빠른지 여부에 관해서는 말할 수 없었습니다.

쿼드 트리가 2D 포인트 세트에 작동하는 것처럼 간단한 이진 트리 가이 경우에 작동해야합니다. 당신의 범위가있는 나무를 만듭니다.

더 설명하기 위해 : 트리의 각 노드에는 범위의 시작과 끝, 잎 노드가 아닌 경우 두 명의 정수가 포함되어 있습니다. 입력 범위에 걸쳐있는 범위를 찾은 다음 트리 상단에서 시작합니다.

  - if the node range intersects the input range:
     - if it's a leaf node, then add the range to your result list
     - if it's not a leaf node, then traverse down to the child nodes and repeat this process.

O (logn) 여야합니다.

자세한 내용 : 이진 트리는 1D 버전의 쿼드 트리처럼 구성됩니다. 각 노드는 3 개의 정수가 있습니다 (위에서 2 개를 말했지만 이제는 3 개가 필요하다는 것을 알고 있습니다.) 노드와 피벗. 왼쪽 자식은이 노드의 피벗에서 가장 낮은 곳에서 파손됩니다. 올바른 아이는이 노드의 피벗 에서이 노드의 가장 높은 곳까지 걸러냅니다. "가장 낮은"에서 "가장 높은"범위가 하나만 있으면 피벗이없고 이것은 잎이 될 것입니다. 이상적으로는 트리의 균형을 유지하기 위해 각 노드의 피벗을 선택합니다.

이 문제가 있었을 때, 나는 정렬 된 범위의 광장과 이진 검색을 사용하여 교차로를 찾았습니다. 이것은 O (log n) 성능이며, 겹치는 범위를 다루기 위해 약간의 오버 헤드가 있습니다.

귀하의 질문에 대한 답은 아래 코드에서 파생 될 수 있지만 삽입이 부족하다는 것입니다. 다른 컨텍스트에 의해 혼란을 피하기 위해 전체 코드를 제시합니다. 다양한 유니 코드 코드 포인트를 코드 포인트 범위 목록에 삽입해야했습니다.

-- 편집하다 --

다중 범위의 교차점을 결정하기 위해 아래 코드를 조정하는 데는 더 이상 교차하지 않는 범위가 발견 될 때까지 삽입 지점에서 사소한 전방 검색이 포함됩니다.

-end edit-

범위 클래스에는 다음이 포함됩니다.

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(lower<oth.lower) { return -1; }
    if(lower>oth.lower) { return  1; }
    if(upper<oth.upper) { return -1; }
    if(upper>oth.upper) { return  1; }
    return 0;
    }

범위 삽입 :

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.length && las>=(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); xa<codepoints.length && codepoints[xa].lower<=las; xa++) {
                if(las<codepoints[xa].upper) { las=codepoints[xa].upper; }
                codepoints[xa]=null;
                rmv=true;
                }
            if(codepoints[idx].lower>fir || codepoints[idx].upper<las) {
                codepoints[idx]=new Range((codepoints[idx].lower < fir ? codepoints[idx].lower : fir),(codepoints[idx].upper>las ? codepoints[idx].upper : las));
                }
            if(rmv) { codepoints=Range.removeNulls(codepoints); }
            }
        }
    return this;
    }

이진 검색 :

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.
        }
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top