문제 링크
주의사항
- JAVA를 사용하여 프로그램을 사용하였습니다.
- 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{
public static void main(String[] args){
}
}
문제 설명
접근 방법
이 문제에 핵심
1. 괄호 문자열에 정의는 문제 설명과 동일하며, 빈 문자열도 괄호 문자열입니다.
2. 괄호 문자열은 ()의 형태로 열림 '(' 과 닫힘 ')'이 매칭되어야 합니다.
3. ㄴㄴ괄호 문자열은 괄호 문자열이 아닌 '(', ')'으로 구성된 문자열입니다.
4. 괄호 문자열은 사전순으로 정렬되며, 0번째부터 시작합니다.
5. N개의 길이를 가지는 괄호 문자열에 대해서 K번째 ㄴㄴ괄호 문자열을 결과로 출력합니다.
6. K번째 ㄴㄴ괄호 문자열이 존재하지 않으면 -1을 결과로 출력합니다.
알고리즘 진행 순서.
1. 입력된 정보를 저장합니다.
2. 점화식을 통해 '('와 남은 문자열 길이에 따라 ㄴㄴ괄호문자열에 대한 개수를 구해서, 조합을 통해서 K번째 ㄴㄴ괄호 문자열을 탐색합니다.
3. 탐색을 통해 얻은 ㄴㄴ괄호 문자열을 결과로 출력합니다.
ㄴㄴ괄호 문자열(다이나믹 프로그래밍)
먼저, 만들어야 하는 문자열의 길이가 짝수일 때와 홀수 일 때로 구분됩니다.
[홀수]
문자열의 길이가 홀수이면, 괄호 문자열을 만들 수 없습니다.
→ '(' 개수와 ')' 개수를 매칭시킬 수 없기 때문입니다.
[짝수]
문자열의 길이가 짝수이면, 괄호 문자열을 만들 수 있습니다.
→ 만들 수 있는 괄호 문자열 개수 - '('와 ')'을 매칭시키는 괄호 문자열의 개수 : ㄴㄴ괄호 문자열 개수
1 | 2 | 3 | 4 | |
0 | 2 | 3 | 8 | 14 |
1 | 1 | 4 | 6 | 0 |
2 | 2 | 3 | 0 | 0 |
3 | 2 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 |
K번째 ㄴㄴ괄호 문자열 만들기(조합)
K번째 ㄴㄴ괄호 문자열을 구할 때에는 2가지를 기준으로 조합을 만들 수 있습니다.
예제입력 2.
1. 입력된 정보를 저장합니다.
N : 4 + 1
※ ㄴㄴ괄호 문자열은 0번째부터 시작하기 때문에 실제로보면 5번째 ㄴㄴ괄호 문자열이기 때문에 +1을 진행하였습니다.
K : 4
2. 점화식을 통해 '('와 남은 문자열 길이에 따라 ㄴㄴ괄호문자열에 대한 개수를 구해서, 조합을 통해서 K번째 ㄴㄴ괄호 문자열을 탐색합니다.
각 문자열 길이에 따른 조합의 개수
길이 | 0 | 1 | 2 | 3 | 4 |
개수 | 1 | 2 | 4 | 8 | 16 |
0 | 1 | 2 | 3 | 4 | |
0 | 0 | 2 | 3 | 8 | 14 |
1 | 1 | 1 | 4 | 6 | X |
2 | 1 | 2 | 3 | X | X |
3 | 1 | 2 | X | X | X |
4 | 1 | X | X | X | X |
3. 탐색을 통해 얻은 ㄴㄴ괄호 문자열을 결과로 출력합니다.
- BufferedReader를 사용하여 입력되는 정보를 저장합니다.
- StringTokenizer을 통해서 N, K의 값을 띄어쓰기 기준 나누었습니다.
- 문자열에 따른 조합 개수를 점화식을 통해 배열에 저장합니다.
- ㄴㄴ괄호 문자열의 개수를 점화식을 통해 DP[][]을 저장합니다.
- 만약, 만들 수 있는 ㄴㄴ괄호 문자열보다 K가 크다면 -1을 BufferedWriter 저장합니다.
- '(', ')'을 사용하는 조건에 따라 K번째 문자열을 탐색합니다.
- 탐색을 통해 얻은 K번째 ㄴㄴ괄호 문자열을 Bufferedwriter 저장합니다.
- BufferedWriter에 저장된 결과를 출력합니다.
결과코드
import java.io.*;
import java.util.StringTokenizer;
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));
StringTokenizer st = new StringTokenizer(br.readLine()," ");
int N = Integer.parseInt(st.nextToken());
long K = Long.parseLong(st.nextToken()) + 1;
//길이가 N개일 때 '(', ')'만 사용하여 만들 수 있는 문자열 개수
long[] combinationCnt = new long[N+1];
//ㄴㄴ괄호 문자열에 대한 조합 DP[i][j]
long[][] DP = new long[N+1][N+1];
combinationCnt[0] = 1;
//문자열 개수 및 DP[i][0]값 초기화
for(int i=1;i<=N;i++){
combinationCnt[i] = combinationCnt[i-1] * 2;
DP[i][0] = 1;
}
//점화식을 이용한 DP[i][j] 메모이제이션 진행
for(int i=1;i<=N;i++) {
DP[0][i] = DP[1][i - 1] + combinationCnt[i - 1];
for (int j = 1; j <= N - i; j++) {
DP[j][i] = DP[j - 1][i - 1] + DP[j + 1][i - 1];
}
}
//ㄴㄴ괄호 문자열 총 개수보다 K가 클 때, -> K번째 문자열을 만들지 못할 때
if((N % 2 == 1 && K > combinationCnt[N]) || (N % 2 == 0 && K > DP[0][N])){
bw.write("-1");
}else{
StringBuilder sb = new StringBuilder();
//현재 '(', ')'을 삽입한 개수
int len = 0;
//'('의 개수
int leftCnt = 0;
//만약 문자열의 개수가 홀수이면, 모든 조합의 개수는 ㄴㄴ괄호 문자열입니다.
boolean flag = N % 2 == 1;
//'(', ')' 조합 진행
while(len < N){
//더 이상 괄호 문자열이 존재하지 않을 때
if(flag){
//')'을 사용할 때
if(K > combinationCnt[N-len-1]){
sb.append(")");
K -= combinationCnt[N-len-1];
}else{ //'('을 사용할 때
sb.append("(");
}
}else{ //괄호 문자열이 존재할 때
//')'을 사용할 때
if(K > DP[leftCnt+1][N-len-1]){
sb.append(")");
K -= DP[leftCnt+1][N-len-1];
leftCnt--; //')'을 사용하기 때문에 '('의 개수가 줄어듭니다.
}else{ //'('을 사용할 때
sb.append("(");
leftCnt++; //'('을 사용하기 때문에 '('의 개수가 증가합니다.
}
}
//')'의 개수가 '('보다 커지면 더 이상 괄호 문자열을 만들 수 없습니다.
if(!flag && leftCnt < 0 ){
flag = true;
}
//문자 선택한 길이
len++;
}
//k번째 문자열 BufferedWriter 저장
bw.write(sb.toString());
}
bw.flush(); //결과 출력
bw.close();
br.close();
}
}
'백준' 카테고리의 다른 글
[백준, Java] 2011번, 암호 코드, (DP) (0) | 2024.05.31 |
---|---|
[백준, Java] 19590번, 비드맨, (그리디) (0) | 2024.05.26 |
[백준, Java] 14939번, 불 끄기, (완전 탐색, 그리드) (0) | 2024.05.11 |
[백준, Java] 21818번, Do You Know Your ABCs?, (완전 탐색) (0) | 2024.05.06 |
[백준, Java] 17240번, Team Selection, (그리드) (0) | 2024.05.06 |
댓글