Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 자바
- 분할정복
- BFS
- java 프로그래머스
- 인텔리제이 에러
- 백준 16935
- 카카오
- 그래프 자바
- 리트코드 1557
- 코딩테스트
- java leetcode
- 자바 5464
- leetcode 1721
- 자바 리트코드
- 프로그래머스
- 코테
- 리트코드
- 백준 18222
- 스택
- 구현
- 파이썬
- 백준
- 리트코드 자바
- leetcode
- 스프링 에러
- DP
- 프로그래머스 java
- daily challenge
- Java
- dfs
Archives
- Today
- Total
레벨업 일지
[Java] leetcode 307. Range Sum Query - Mutable 본문
문제
https://leetcode.com/problems/range-sum-query-mutable/
알아야 할 개념
- 세그먼트 트리
풀이
풀이 알고리즘은 다음과 같다.
- 세그먼트 트리 클래스를 구현.
- 트리 클래스의 메소드를 호출하여 정답을 리턴.
세그먼트 트리란?
세그먼트 트리(Segment Tree)는 구간 쿼리를 효율적으로 처리하기 위한 이진 트리 자료구조입니다. 구간 합, 최소값, 최대값 등과 같은 구간 쿼리를 빠르게 수행할 수 있도록 설계되어 있습니다. 세그먼트 트리는 배열을 분할하고 각 구간에 대한 값을 노드에 저장하여 사용합니다.
class Smt{
int tree[]; //세그먼트 트리 배열
int size; // 트리 사이즈
...
}
세그먼트 트리(SMT) 초기화
- 배열을 기반으로 세그먼트 트리를 구성한다. 이때 트리 초기 사이즈는 len( 배열 ) * 4 이다.
이진 트리 기반으로 트리를 만들고 Left, Right 탐색인덱스가 최대 (root.index * 2 + 2 ) 이기 때문에 arr.length * 4 를 해주면 배열 인덱스 충돌없이 커버 가능하다.
public void initTree(int start, int end, int rootIdx, int[] arr){
if(start > end)return;
if(start == end){
tree[rootIdx] = arr[start];
return;
}
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
initTree(start, P, L, arr);
initTree(P+1, end, R, arr);
tree[rootIdx] = tree[L] + tree[R];
}
그다음, 배열의 특정 원소를 변경하거나 추가할 때 세그먼트 트리를 업데이트 수도 & 구현 코드이다.
getVal (현재 범위 start, 현재 탐색 범위 end, 현재 세그먼트 트리 루트 인덱스, 목표 범위 start, 목표 범위 end){
// 목표 범위가 현재 범위 밖에 있다면 0 반환
if (목표 범위 시작 > 현재 범위 끝 || 목표 범위 끝 < 현재 범위 시작) return 0;
left 탐색 + right 탐색 한 값 리턴.
}
setVal(현재 시작과 끝 범위, 현재 루트 인덱스, 목표 idx, 더해줄 차이 값){
// 목표 인덱스가 현재 범위 밖에 있다면 종료.
if (현재 범위 시작 > 현재 범위 끝 || 목표 인덱스 < 현재 범위 시작 || 목표 인덱스 > 현재 범위 끝) return;
// 현재 루트 인덱스에 차이값을 더함
tree [현재 세그먼트 트리 루트 인덱스] += 차이값;
// 현재 범위 시작과 끝이 같다면 리턴 (리프 노드)
if (현재 범위 시작 == 현재 범위 끝) return;
Left , Right 탐색
}
public int getVal(int start, int end, int rootIdx, int targets, int targete){
if(targets > end || targete < start) return 0;
if(targets <= start && targete >= end)return tree[rootIdx];
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
return getVal(start, P, L, targets, targete ) + getVal(P+1, end, R, targets, targete);
}
public void setVal(int start, int end, int rootIdx, int targetIdx, int dif){
if(start > end || targetIdx < start || targetIdx > end)return;
tree[rootIdx] += dif;
if(start == end)return;
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
setVal(start, P, L,targetIdx, dif);
setVal(P+1, end, R,targetIdx, dif);
}
그림을 그려가며 따라가면 이해가 쉽다.
코드
전체 코드는 다음과 같다.
자바
class Smt{
int tree[];
int size;
Smt(int arr[]){
size = arr.length*4;
tree = new int[size];
initTree(0, arr.length-1, 0 , arr);
}
public void initTree(int start, int end, int rootIdx, int[] arr){
if(start > end)return;
if(start == end){
tree[rootIdx] = arr[start];
return;
}
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
initTree(start, P, L, arr);
initTree(P+1, end, R, arr);
tree[rootIdx] = tree[L] + tree[R];
}
public int getVal(int start, int end, int rootIdx, int targets, int targete){
if(targets > end || targete < start) return 0;
if(targets <= start && targete >= end)return tree[rootIdx];
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
return getVal(start, P, L, targets, targete ) + getVal(P+1, end, R, targets, targete);
}
public void setVal(int start, int end, int rootIdx, int targetIdx, int dif){
if(start > end || targetIdx < start || targetIdx > end)return;
tree[rootIdx] += dif;
if(start == end)return;
int L = rootIdx * 2 + 1;
int R = rootIdx * 2 + 2;
int P = start + (end - start)/2;
setVal(start, P, L,targetIdx, dif);
setVal(P+1, end, R,targetIdx, dif);
}
}
class NumArray {
Smt smt;
int nums[];
public NumArray(int[] nums) {
this.nums = nums;
smt = new Smt(nums);
}
public void update(int index, int val) {
int dif = val - nums[index];
nums[index] = val;
smt.setVal(0, nums.length-1, 0,index, dif);
}
public int sumRange(int left, int right) {
return smt.getVal(0, nums.length-1,0, left, right);
}
}
'알고리즘 > leetcode' 카테고리의 다른 글
[Java] leetcode 1721. Swapping Nodes in a Linked List (1) | 2023.05.16 |
---|---|
[Java] leetcode 30. Substring with Concatenation of All Words (0) | 2023.05.06 |
[Java] leetcode 662. Maximum Width of Binary Tree (0) | 2023.04.20 |
leetcode 946. Validate Stack Sequences (0) | 2023.04.13 |
leetcode 508. Most Frequent Subtree Sum (0) | 2023.04.12 |
Comments