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); } };