문제

칸토어 집합은 0과 1사이의 실수로 이루어진 집합으로, 구간 [0, 1]에서 시작해서 각 구간을 3등분하여 가운데 구간을 반복적으로 제외하는 방식으로 만든다.

전체 집합이 유한이라고 가정하고, 다음과 같은 과정을 통해서 칸토어 집합의 근사를 만들어보자.

1. -가 3N개 있는 문자열에서 시작한다.

2. 문자열을 3등분 한 뒤, 가운데 문자열을 공백으로 바꾼다. 이렇게 하면, 선(문자열) 2개가 남는다.

3. 이제 각 선(문자열)을 3등분 하고, 가운데 문자열을 공백으로 바꾼다. 이 과정은 모든 선의 길이가 1일때 까지 계속 한다.

예를 들어, N=3인 경우, 길이가 27인 문자열로 시작한다.

---------------------------

여기서 가운데 문자열을 공백으로 바꾼다.

---------         ---------

남은 두 선의 가운데 문자열을 공백으로 바꾼다.

---   ---         ---   ---

한번 더

- -   - -         - -   - -

모든 선의 길이가 1이면 멈춘다. N이 주어졌을 때, 마지막 과정이 끝난 후 결과를 출력하는 프로그램을 작성하시오.

입력

입력을 여러 줄로 이루어져 있다. 각 줄에 N이 주어진다. 파일의 끝에서 입력을 멈춘다. N은 0보다 크거나 같고, 12보다 작거나 같은 정수이다.

출력

입력으로 주어진 N에 대해서, 해당하는 칸토어 집합의 근사를 출력한다.

 

예제 입력 1

0
1
3
2

예제 출력 1

-
- -
- -   - -         - -   - -
- -   - -

 

EOF(End Of File)

기존의 백준 문제는 항상 입력 문장의 개수를 파악할 수 있었는데, 이번 문제는 파일의 끝에서 입력을 멈추어야 해서 당황했다. 구글링해보니 다양한 방법이 있었는데, 그 중 EOF를 사용하는 방법으로 해결했다.

 

EOF란, End Of File의 줄임말로, 파일의 끝을 나타낸다, 이는 사용자가 더 이상 데이터를 읽을 수 없는 지점으로, 이 곳에 도달하게 되면 빈문자열이 출력으로 반환된다.

EOF를 사용하기 위해 무한으로 반복되는 while문 안에 try와 except를 사용하여 예외 처리를 진행할 것이다.

입력이 있을 땐 try문에 있는 코드들을 실행시키고, 입력이 없을 경우 break를 통해 while 문의 반복을 멈춘다.

 

풀이 1 - 메모리 초과

- 분할 정복(Divide and Conquer) 알고리즘의 재귀 방식을 이용하여 해결해보려고 했다.

// [BOJ] 4779. 칸토어 집합

import java.io.*;

// public
class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            try {
                int N = Integer.parseInt(br.readLine());
                String answer = divideAndConquer(N);

                System.out.println("answer : " + answer);
            } catch (Exception e) {
                break;
            }
        }
    }

    public static String divideAndConquer(int n) {
        if (n == 0) return "-";

        String blanks = "";
        for (int i = 0 ; i < Math.pow(3, n - 1); i++) {
            blanks += " ";
        }

        return divideAndConquer(n - 1) + blanks + divideAndConquer(n - 1);
    }
}

해당 풀이는 메모리 초과가 났는데, 재귀를 들어가면서 반환되는 문자열들의 길이가 3^12 = 531441, 3^11 = 177147, ... 로 메모리를 많이 사용하기 때문인 것으로 추측된다.

 

풀이 2 - StringBuilder 이용

Java의 String의 경우 특정 인덱스에 위치한 원소값을 수정할 수 없지만 StringBuilder를 사용하면 setCharAt 메소드를 이용하여 수정이 가능하다고 한다. 때문에 매번 새로운 객체를 생성하는 String을 사용할 때보다 메모리를 크게 줄일 수 있다.

// [BOJ] 4779. 칸토어 집합

import java.io.*;

// public
public class Main {
    public static StringBuilder sb;
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            try {
                int N = Integer.parseInt(br.readLine());
                sb = new StringBuilder();
                for (int i = 0; i < (int) Math.pow(3, N); i++) {
                    sb.append("-");
                }

                divideAndConquer(0, (int) Math.pow(3, N));

                System.out.println(sb);
            } catch (Exception e) {
                break;
            }
        }
    }

    public static void divideAndConquer(int start, int size) {
        if (size == 1) return;

        int newSize = size / 3;
        for (int i = start + newSize; i < start + 2 * newSize; i++) {
            sb.setCharAt(i, ' ');
        }

        divideAndConquer(start, newSize);
        divideAndConquer(start + 2 * newSize, newSize);
    }
}

'Algorithm' 카테고리의 다른 글

[LeetCode] 2695. Array Wrapper  (0) 2024.01.31
[LeetCode] 2677. Chunk Array  (0) 2024.01.31
[SWEA] 1230. 암호문3  (1) 2024.01.29
[SWEA] 10726. 이진수 표현  (0) 2024.01.29
[SWEA] 1288. 새로운 불면증 치료법  (0) 2024.01.29

문제

https://swexpertacademy.com/main/solvingProblem/solvingProblem.do

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

접근 방식

1. 암호문의 중간에서 삽입 혹은 삭제하는 명령어가 있기 때문에 삽입 및 삭제 연산이 자주 발생할 때 유리한 LinkedList 자료구조를 사용한다.

2. 각 명령어들을 `switch case`문을 사용하여 적절하게 분기 처리한다.

 

// [SWEA] 1230. 암호문3

import java.util.*;
import java.io.*;

// public
class Solution {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;

        int T = 10;

        for (int tc = 1; tc <= T; tc++) {
            int N = Integer.parseInt(br.readLine());
            st = new StringTokenizer(br.readLine());
            LinkedList<String> passwords = new LinkedList<>();
            
            for (int i = 0; i < N; i++) {
                passwords.add(st.nextToken());
            }

            int M = Integer.parseInt(br.readLine());
            st = new StringTokenizer(br.readLine());
            int x, y;
            for (int i = 0; i < M; i++) {
                char command = st.nextToken().charAt(0);
                x = Integer.parseInt(st.nextToken());

                // 각 명령어에 따라 제어 과정을 나눈다.
                switch (command) {

                    // 명령어가 I(삽입)일 경우
                    case 'I':

                        // 앞에서부터 X번째 암호문 바로 다음에 y개의 암호문을 삽입한다.
                        y = Integer.parseInt(st.nextToken());
                        for (int j = 0; j < y; j++) {
                            String password = st.nextToken();
                            passwords.add(x, password);
                            x += 1;
                        }
                        break;
                    
                    // 명령어가 D(삭제)인 경우
                    case 'D':

                        // 앞에서부터 x번째 암호문 바로 다음부터 y개의 암호문을 삭제한다.
                        y = Integer.parseInt(st.nextToken());
                        for (int j = 0; j < y; j++) {
                            passwords.remove(x);
                        }
                        break;

                    // 명령어가 A(추가)인 경우
                    case 'A':

                        // 암호문 뭉치 맨 뒤에 x개의 암호문을 덧붙인다.
                        for (int j = 0; j < x; j++) {
                            passwords.add(st.nextToken());
                        }
                        break;
                    
                    default:
                        break;
                }
            }

            sb.append("#").append(tc).append(" ");

            // 수정된 결과의 처음 10개 암호문을 출력한다.
            for (int i = 0; i < 10; i++) {
                sb.append(passwords.get(i)).append(" ");
            }

            sb.append("\n");
        }

        System.out.println(sb);
    }
}

'Algorithm' 카테고리의 다른 글

[LeetCode] 2677. Chunk Array  (0) 2024.01.31
[BOJ] 4779. 칸토어 집합  (1) 2024.01.30
[SWEA] 10726. 이진수 표현  (0) 2024.01.29
[SWEA] 1288. 새로운 불면증 치료법  (0) 2024.01.29
[LeetCode] 2667. Create Hello World Function  (0) 2024.01.29

문제 

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AXRSXf_a9qsDFAXS

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

접근 방법

1. M의 이진수 표현의 마지막 N개의 비트가 모두 켜져 있다면, (M + 1)는 2^N의 배수이다.

2. 따라서 (M + 1)가 2^N으로 나누어 떨어진다면 "ON"을 출력하고, 그렇지 않다면 "OFF"를 출력한다.

 

풀이

// [SWEA] 10726. 이진수 표현

import java.util.*;
import java.io.*;

// public
class Solution {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;

        int T = Integer.parseInt(br.readLine());

        for (int tc = 1; tc <= T; tc++) {
            st = new StringTokenizer(br.readLine());
            int N = Integer.parseInt(st.nextToken());
            int M = Integer.parseInt(st.nextToken());
            
            sb.append("#").append(tc).append(" ").append((M + 1) % (1 << N) == 0 ? "ON" : "OFF").append("\n");
        }
        
        System.out.println(sb);
    }
}

'Algorithm' 카테고리의 다른 글

[BOJ] 4779. 칸토어 집합  (1) 2024.01.30
[SWEA] 1230. 암호문3  (1) 2024.01.29
[SWEA] 1288. 새로운 불면증 치료법  (0) 2024.01.29
[LeetCode] 2667. Create Hello World Function  (0) 2024.01.29
[LeetCode] 2666. Allow One Function Call  (0) 2024.01.26

문제

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV18_yw6I9MCFAZN

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

접근 방법

// [SWEA] 1288. 새로운 불면증 치료법

import java.util.*;
import java.io.*;

// public
class Solution {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        // 테스트 케이스의 수
        int T = Integer.parseInt(br.readLine());
        
        for (int tc = 1; tc <= T; tc++) {
            int N = Integer.parseInt(br.readLine());

            // k번째에 센 양의 횟수
            int accNum = 0;

            // 비트연산을 통해 각 숫자가 저장되었는지를 확인할 수 있는 변수
            int numCnt = 0;

            // 0 ~ 9까지 모든 숫자를 탐색하였다면 numCnt는 1111111111(2)로, 1023이 될 것이다.
            // 즉 numCnt 값이 1023이 될 때까지 반복
            while (numCnt < 1023) {

                // accNum에 N을 더함.
                accNum += N;

                // curNum에 현재 누적값 추가
                int curNum = accNum;

                // 각 자리수를 순회하며
                while (curNum > 0) {

                    // 해당 자리수의 숫자에 해당하는 비트 위치와 numCnt를 OR 연산시킨다.
                    numCnt = numCnt | (1 << (curNum % 10));

                    curNum /= 10;
                }
            }
            
            // 0 ~ 9까지의 모든 숫자가 나왔을 때의 accNum을 출력한다.
            sb.append("#").append(tc).append(" ").append(accNum).append("\n");
        }

        System.out.println(sb);
    }
}

'Algorithm' 카테고리의 다른 글

[SWEA] 1230. 암호문3  (1) 2024.01.29
[SWEA] 10726. 이진수 표현  (0) 2024.01.29
[LeetCode] 2667. Create Hello World Function  (0) 2024.01.29
[LeetCode] 2666. Allow One Function Call  (0) 2024.01.26
[LeetCode] 2665. Counter II  (0) 2024.01.25

+ Recent posts