세그먼트 트리 - "- 수정 배열 지역 및 (307)를 검색"

leetcode  307 지역 및 검색 - 배열을 수정할 수 있습니다

I를 포함하는 요소 (I ≤ j)는, j 개의 점의 범위 내에서 J 행 I 인덱스의 합 정수 nums 배열의 배열 요소를 감안.

업데이트 (나, 발) 함수에 따라서 열 수가 수정할 제가 발이다 첨자의 값으로 업데이트 될 수있다.

예 :

주어 nums = [ 1, 3, 5 ] 

sumRange ( 0, 2) -> 9 
업데이트 ( 1, 2 ) 
sumRange ( 0, 2) -> 8

 

출처 : 숙박 버튼 (LeetCode)
링크 : HTTPS : //leetcode-cn.com/problems/range-sum-query-mutable는
모든 네트워크에서 공제 저작권. 상업 무단 전재 소스를 표시하시기 바랍니다 승인 된 공식, 비상업적 재판에 문의하시기 바랍니다.

 

바이두 백과 사전의 정의에 트리 라인 :

세그먼트 트리는 인 이진 검색 트리 간격 트리 가 간격 세그먼트 트리의 각 단위 구간에 대응하는 리프 노드들로 분할 단면을 의미하고, 유사하다.
각 세그먼트가 아닌 트리 들어 리프 노드 [A, B], 간격의 좌측 아들 [A, (A +의 b)로 표시 / 2], 오른쪽 아들 (A + B를)로 표시되는 세그먼트 / 2 + 1, B]. 따라서 세그먼트 트리는 균형 이진 트리 , 자식 노드의 마지막 숫자는 N, 즉, 선 단면의 전체 길이이다.
세그먼트 트리를 사용하면 신속하게 선 세그먼트의 수에 나타나는 특정 노드의 수를 찾을 수있는 시간 복잡도 O (logN)의합니다. 의 최적화없이 공간의 복잡성이 2N, 그래서 때로는 별도의 공간 압축을 확인해야합니다.
 
 
어레이 작업의 상당한 숫자의 주제 때문에 수정합니다 :
원래의 데이터 구조에 직접, 즉 배열을 수정하고, 각 수정 O 걸릴 경우 (1), 각각의 시간 간격 및 출력은 O (N) 시간 복잡도 걸릴
(2) 그러나 우리는 간격과 트리 라인, 및 O (logn) 시간 복잡도를 가지고 각 변경의 출력을 설정할 때
 
이진 트리 구조는 세그먼트 트리를 구성합니다 :
클래스 NumArray { 
    TreeNode를의 *의 루트; 
    벡터 < INT > NUM;
    INT N;
공개 : 

    NumArray (벡터 < INT > & nums) { 
        N = nums.size () - 1 ; 
        NUM = nums;
        경우 (N> = 0 ) 
            루트 = creatTree (nums, 0 , N); //针对初始化时数组为[] 
    } 

    의 TreeNode * creatTree (벡터 < INT > & nums, INT (X), INT  Y)
    {
        만약 (== X , Y) 
        { 
            의 TreeNode * TMP = 의 TreeNode (nums [X]);
            반환 TMP; 
        } 
        다른 
        { 
            INT의 합 = 0 ;
             ( INT의 I = X; I <= Y; I ++ ) 
            { 
                합계 + = nums [I]; 
            } 
            의 TreeNode * TMP = 의 TreeNode (합);
            INT 중간 = (X + Y) / 2 ; 
            TMP -> 왼쪽 =  creatTree (nums, 배, 중간)
            TMP-> 오른쪽 = creatTree (nums 중간 + 1 , Y);
            반환 TMP; 
        } 
    } 
    
    공극 업데이트 ( INT I, INT 브로) { 
        의 TreeNode * R = 루트;
        INT leftBorder = 0 , rightBorder = N;
        반면 (R) - 
        { 
            (R) -> 발 = R-> 발 - NUM [I] + 브로;
            INT의 중간 = (leftBorder rightBorder +) / 2 ;
            경우 (ⅰ <= 미드)가 
            { 
                R = R ->은 왼쪽;
                rightBorder = 중간; 
            } 
            다른 
            { 
                R = R -> 오른쪽; 
                leftBorder = 중간 + 1 ; 
            } 
        } 
        NUM [I] = 브로; 
    } 
    INT의 합 (TreeNode에 *이 R은 int로INT J, INT leftBorder, INT rightBorder) 
    { 
        경우 (R == NULL) 반환  0 ;
        경우 (I == leftBorder && J == rightBorder) 복귀 R-> 발;
        INT의 중간 = (leftBorder rightBorder +) / 2 ;
        경우 (ⅰ <= 중간 && J> MID) 
        { 
            리턴 합 (R-> 좌, 전, 중, leftBorder 미드) + SUM (R-> 우측 중간 + 1 , J 중간 + 1 , rightBorder); 
        } 
        다른  경우 (ⅰ <= MID) 
        { 
            리턴 합 (R-> 좌, I, J, leftBorder 미드); 
        } 
        다른  경우 (I> MID) 
        { 
            리턴 합 (R-> 오른쪽, I, J, 미드 + 1 , rightBorder); 
        } 
        반환 INT_MAX을; 
    }
    INT sumRange ( INT I, INT의 J) { 
        의 TreeNode * R = 루트;
        리턴 합 (R, I, J, 0 , N); 
    } 
}; 

/ * * 
 * 귀하의 NumArray 개체가 같은 인스턴스 및 호출됩니다 : 
 * NumArray * OBJ = 새로운 NumArray (nums); 
 *를 OBJ> 업데이트 (I, 발); 
 * = INT PARAM_2를 OBJ> sumRange (I, J); 
 * /

 

조직 세그먼트 트리 펜윅 나무 :

클래스 NumArray { 
    벡터 < INT > segmTree;
    INT N;
공개 : 
    NumArray (벡터 < INT > & nums) { 
        N = nums.size () - 1 ;
        경우 (N> = 0 ) 
            buildSegmTree (nums, 0 , 0 , N); 
    } 
   //自底向上建树
    공극 buildSegmTree (벡터 < INT > & nums, INT CUR, 하는 int , 시작 INT 단부) 
    { 
        하면서(현재> = segmTree.size ()) segmTree.push_back ( 0 );
        경우 (== 시작 단부) 
        { 
            segmTree를 [CUR] = nums는 [시작]; 
        } 
        다른 
        { 
            INT 중반 = (+ 끝 시작) / 2 ;
            INT는 = CUR * 좌측 2 + 1 ; //左子区间下标
             INT 오른쪽 = CUR * 2 + 2 ] //右子区间下标
            buildSegmTree (nums, 왼쪽, 중순 시작) 
            buildSegmTree (nums 오른쪽 중간 + 1 , 종료); 
            segmTree [CUR]segmTree = [좌측] + segmTree [오른쪽]; 
        } 
    } 
  //自底向上更新
공극 updateSegmTree ( INT의 CUR, 하는 int , 시작 INT , 끝을 int로 난을 INT 브로) { 경우 (> 단부 시작) 복귀 ; 경우 (== 시작 단부) { segmTree [CUR] = 브로; 반환 ; } INT 중간 = (+ 단부 시작) / 2 ; INT는 왼쪽 = 2 * CUR + 1; INT 오른쪽 = 2 * CUR + 2 ; 경우 (ⅰ <= 중간 && I> = 시작) { updateSegmTree (왼쪽, 시작, 중간, I, 발); } 다른 { updateSegmTree (오른쪽 미드 + 1 , 단, I, 발); } segmTree [CUR] = segmTree [왼쪽] + segmTree [오른쪽]; } 공극 업데이트 ( INT I, INT 브로) { updateSegmTree ( 0 , 0 , N, I, 발); }
  //自顶向下找区间
INT의 합 ( INT의 CUR는 int로INT J가 하는 int , 시작 INT 단부) { 경우 (I> J 단부 || <시작) 반환 0 ; 경우 는 (i = 단부 <= J가 && 시작>)를 반환 segmTree를 [CUR]; INT 중간 = / (+ 단부 시작) 2 ; INT는 = CUR * 좌측 2 + 1 ; INT의 오른쪽 = CUR * 2 + 2 ] 리턴 합 (왼쪽 난, J, 시작 MID) + SUM (오른쪽, I, J, 미드 + 1최종); } INT sumRange ( INT I, INT의 J) { 리턴 합 ( 0 , I, J, 0 , N); } };

 

추천

출처www.cnblogs.com/Dancing-Fairy/p/12605309.html