문제 링크
주의사항
- JAVA를 사용하여 프로그램을 사용하였습니다.
- 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{
public static void main(String[] args){
}
}
문제 설명
접근 방법
이 문제에 핵심
1. N개의 음이 아닌 정수가 주어집니다.
2. N개의 정수 중 2개를 선택해서 XOR을 하였을 때 최대값을 결과로 출력합니다.
알고리즘 진행 순서.
1. 입력된 정보를 저장합니다.
2. 트라이 자료구조를 N개의 수를 저장하면서 최대값을 탐색합니다.
3. 탐색해서 얻은 최대값을 결과로 출력합니다.
트라이 자료구조를 이용하여 N개의 수 적립
트라이에 대한 기본적인 지식이 없으시다면, 아래에 내용을 정독하시는 것을 추천드립니다.
우리는 N개의 수에 대해서 XOR을 진행할 것이기 때문에 N개의 수를 Bit 형태로 저장할 것입니다.
예를 들어, 7이라는 값은
111의 값이 저장될 것입니다.
하지만, 저희가 최대값을 찾아야 하기 때문에 N이 주어지는 최대값 1,000,000,000을 수용할 수 있는 Bit을 기반으로 작업할 것입니다.
결과적으로 111의 값이 들어가는 형태 : 0000000000000000000000000000111
트라이 자료구조를 이용하여 XOR의 최대값 비교해보기
N개의 수를 저장할 때마다 현재까지 Trie에 저장된 값들과 비교를 진행합니다.
저장할 때마다 비교를 진행할 수 있는 이유는
4개의 수를 진행할 때, 위 그림처럼 모든 경우를 비교할 수 있기 때문입니다.
XOR에 대한 최대값 비교하기
XOR의 최대값이 되려면 해당 값에 Bit와 반대가 되어야 큰 값을 이룰 수 있습니다.
예를 들어, 10001에 대한 XOR을 진행해서 최대값이 되려면
10001의 반대값 01110이 되어야 합니다.
10001 XOR 01110 = 11111으로 최대값을 구성할 수 있습니다.
Trie에 저장된 값들을 비교할 때
현재 비트의 값 : 1
▶ 현재 Trie의 자식 노드에서 0을 가리키는 노드가 존재하는지 확인
▷ 0을 가리키는 노드가 존재하면 해당 노드로 이동
▷ 0을 가리키는 노드가 존재하지 않으면 1을 가리키는 노드로 이동
현재 비트의 값 : 0
▶ 현재 Trie의 자식 노드에서 1을 가리키는 노드가 존재하는지 확인
▷ 1을 가리키는 노드가 존재하면 해당 노드로 이동
▷ 1을 가리키는 노드가 존재하지 않으면 0을 가리키는 노드로 이동
위 비교 과정을 통해서 최대값을 결과로 출력하면 됩니다.
※예제입력 과정을 확인하시면 이해하시기 편하실 것입니다.
비슷한 문제를 풀어보시려면 아래의 문제를 추천드립니다.
예제입력 1.
1. 입력된 정보를 저장합니다.
N : 5
수 | 1 | 2 | 3 | 4 | 5 |
Bit | 1 | 10 | 11 | 100 | 101 |
2. 트라이 자료구조를 N개의 수를 저장하면서 최대값을 탐색합니다.
첫 번째 수 : 1(1)을 Trie 저장
첫 번째 수는 두 수를 XOR할 수 없기 때문에 비교하는 과정을 생략합니다.
두 번째 수 : 2(10)을 Trie 저장
XOR 비교하기
2 ▶ 0000000000000000000000000000010
최상의 값 : 1111111111111111111111111111111111101
하지만, 현재의 값에서 트라이에 저장된 값에 Trie에 대한 비교를 진행하면
0000000000000000000000000000001 가장 XOR의 큰 값을 얻을 수 있습니다.
0000000000000000000000000000010 XOR 0000000000000000000000000000001
▶ 0000000000000000000000000000011 = 3
세 번째 수 : 3(11)을 Trie 저장
XOR 비교하기
3 ▶ 0000000000000000000000000000011
최상의 값 : 1111111111111111111111111111111111100
하지만, 현재의 값에서 트라이에 저장된 값에 Trie에 대한 비교를 진행하면
0000000000000000000000000000001 가장 XOR의 큰 값을 얻을 수 있습니다.
0000000000000000000000000000011 XOR 0000000000000000000000000000001
▶ 0000000000000000000000000000010 = 2
네 번째 수 : 4(100)을 Trie 저장
XOR 비교하기
4 ▶ 0000000000000000000000000000100
최상의 값 : 1111111111111111111111111111111111011
하지만, 현재의 값에서 트라이에 저장된 값에 Trie에 대한 비교를 진행하면
0000000000000000000000000000011 가장 XOR의 큰 값을 얻을 수 있습니다.
0000000000000000000000000000100 XOR 0000000000000000000000000000011
▶ 0000000000000000000000000000111 = 7
다섯 번째 수 : 5(101)을 Trie 저장
XOR 비교하기
5 ▶ 0000000000000000000000000000101
최상의 값 : 1111111111111111111111111111111111010
하지만, 현재의 값에서 트라이에 저장된 값에 Trie에 대한 비교를 진행하면
0000000000000000000000000000010 가장 XOR의 큰 값을 얻을 수 있습니다.
0000000000000000000000000000101 XOR 0000000000000000000000000000010
▶ 0000000000000000000000000000111 = 7
3. 탐색해서 얻은 최대값을 결과로 출력합니다.
탐색을 통해 최대값 : 7
7을 결과로 출력 합니다.
- BufferedReader를 사용하여 입력되는 정보를 저장합니다.
- StringTokenizer를 이용하여 N개의 수를 띄어쓰기 기준 저장합니다.
- N개의 수를 저장할 Trie을 생성합니다.
- 첫 번째 수와 Root Node을 생성한 뒤 2 ~ N번째 수에 대해서 Trie에 저장 및 XOR 비교를 진행합니다.
- 비교가 끝난 뒤 최대값을 BufferedWriter 저장합니다.
- BufferedWriter에 저장된 결과를 출력합니다.
- Node 클래스는 Trie에 각 노드를 정의한 것으로써, 2개의 Bit의 Index를 가리키는 int[2] 배열을 가지고 있습니다.
- Trie클래스는 자료구조 Trie을 구현한 것입니다.
- Trie의 init은 자식 노드를 생성하는 함수입니다.
- Tire의 insert는 Bit의 정수를 저장하는 Trie의 저장하는 함수입니다.
- Trie의 search는 XOR을 진행할 때 최대값이 될 수 있는 값을 구하는 함수입니다.
결과코드
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
//Trie에 대한 Node 값
class Node{
int[] child;
//Node 생성자
Node(){
//Bit는 0, 1이기 때문에 [2]로 배열 초기화
child = new int[2];
//자식 노드가 없으면 -1로 표시
Arrays.fill(child, -1);
}
}
//Trie 관한 클래스
class Trie{
//노드에 정보 저장하는 List
List<Node> nodes;
Trie(){
nodes = new ArrayList<>();
}
//노드 생성 및 Index 반환하는 함수
int init(){
Node newNode = new Node();
nodes.add(newNode);
return nodes.size() - 1;
}
//Bit의 수를 추가하는 함수
void insert(int cur, int idx, int val){
if(idx == -1){
return;
}
//현재 비트의 값
int c = (val & (1 << idx)) == 0 ? 0 : 1;
//해당 자식 노드가 없을 때 노드 생성
if(nodes.get(cur).child[c] == -1){
int nxtIdx = init();
nodes.get(cur).child[c] = nxtIdx;
}
//다음 Bit값으로 이동
insert(nodes.get(cur).child[c], idx - 1, val);
}
//XOR 비교하는 함수
int search(int cur, int idx, int val, int sum){
if(idx == -1){
return sum;
}
//0 → 1, 1 → 0으로 변환
int c = 1 - ((val & (1 << idx)) == 0 ? 0 : 1);
//해당 자식 노드가 없으면 다시 원상태로 변환
if(nodes.get(cur).child[c] == -1){
c = 1 - c;
}
//다음 Bit 값 비교
return search(nodes.get(cur).child[c], idx - 1, val, sum + (c << idx));
}
}
public class Main {
public static void main(String[] args) throws IOException {
//입력값 처리하는 BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//결과값 출력하는 BufferedWriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int N = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine()," ");
int ans = Integer.MIN_VALUE;
//Tire 생성
Trie trie = new Trie();
//Root Node 생성
trie.init();
//첫 번째 수 Trie에 저장
trie.insert(0, 30, Integer.parseInt(st.nextToken()));
//2 ~ N번째 수 Trie 저장 및 XOR 비교
for(int i=1;i<N;i++){
int val = Integer.parseInt(st.nextToken());
//현재 수 Trie 저장
trie.insert(0, 30, val);
//XOR비교를 통해 최대값 비교
ans = Math.max(ans, trie.search(0, 30, val, 0) ^ val);
}
//최대값 BufferedWriter 저장
bw.write(String.valueOf(ans));
bw.flush(); //결과 출력
bw.close();
br.close();
}
}
'백준' 카테고리의 다른 글
[백준, Java] 1497번, 기타콘서트(백트래킹) (0) | 2023.12.09 |
---|---|
[백준, Java] 1981번, 배열에서 이동(BFS, 이분탐색) (2) | 2023.12.04 |
[백준, Java] 27281번, 운전병의 딜레마(다익스트라, 이분탐색) (2) | 2023.11.19 |
[백준, Java] 1726번, 로봇(다익스트라) (2) | 2023.11.11 |
[백준, Java] 16965번, 구간과 쿼리(BFS) (0) | 2023.11.07 |
댓글