반응형
이번에는 2개의 문제를 합쳐서 피라미드를 만들어 보자.
1, 3, 5, 7
1부터 2씩 증가하여 별을 가운데 정렬하는 구조이다.

*
***
*****
*******
*********

문제 핵심

  • 1 <= N <= 100
  • 2 * N - 1 개의 별을 찍어낸다고 한다.
  • 가운데 정렬로 별을 1부터 2씩 증가하여 출력하여 피라미드를 만들어 내는 구조

풀이 과정

별 찍기 1과 같이 이차원 배열을 통해 그려나가는 방식이 있고, 공백의 개수와 별의 개수의 규칙을 찾아 그려나갈 수 있다.

 

다음 풀이는 규칙을 찾아 문제를 풀어나가는 경우이다.

1. N이 5일 때 공백의 개수는 N - 1, N - 2, ..., 0개이다.

2. 이 때 별의 개수는 1부터 시작하여 2개씩 더해진다. 즉 홀수로 진행된다.

3. 각각의 층은 N, N + 1, N + 2, ..., N * 2 - 1로 증가된다.

4. 1부터 N + i까지 항상 반복하면 i값에 따라 3번의 조건을 만족하고 j < N - i값에 따라 공백은 점차 줄어들게 된다.

5. 나머지를 별로 채움으로써 피라미드처럼 나오게 된다.

for (int i = 0; i < N; i++) {
    for (int j = 1; j <= N + i; j++) {
        if(j < N - i) {
            stringBuilder.append(' ');
        }
        else {
            stringBuilder.append('*');
        }
    }
    stringBuilder.append('\n');
}

 

벌써부터 별 찍기가 재밌어 진다. 
아직까지는 조금만 생각하면 금방 풀 수 있는 문제이다.
개인적으로 단계적 풀이를 제외하고 모든 별찍기를 풀고자 한다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < N; i++) {
            for (int j = 1; j <= N + i; j++) {
                if(j < N - i) {
                    stringBuilder.append(' ');
                }
                else {
                    stringBuilder.append('*');
                }
            }
            stringBuilder.append('\n');
        }

        System.out.println(stringBuilder);
    }
}
반응형
반응형
이번에는 2번 문제와 같이 오른쪽 벽에 붙어 별을 그려나가는 방식이다.
좌우 대칭으로 숫자를 바꿔 생각하면 편하다.
 

[ 백준 2439번 문제 ] 별 찍기 - 2 - JAVA

이전 별 찍기에서 생각했던 공백을 생각해야 하는 문제가 나왔다.N * N의 크기로 생각했을 때 공백과 별 위치를 생각하면 풀면 된다. [ 백준 2438번 문제 ] 별 찍기 - 1 - JAVA단계적 풀이라는 카테고

p-coding.tistory.com

문제 핵심

  • 1 <= N <= 100
  • N 별 개수를 시작으로 점점 줄여나가 왼쪽 벽에 붙여 나가는 과정
  • 즉 공백이 0 ~ N - 1까지 별의 개수가 N ~ 1 개까지 

풀이 과정

조건문을 사용하여 공백부터 나왔던 값을 별부터 나오게 끔 변경하면 된다.

 

1. i를 통해 N번 반복

2. j를 통해 j < i 인 경우에만 공백 처리, i 값이 증가함에 따라 0, 1, 2, 3, 4 ~ N - 1번 공백을 출력

3. 그 외의 조건은 모두 별로 처리

for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
        if(j < i) {
            str.append(' ');
        }
        else {
            str.append('*');
        }
    }
    str.append('\n');
}

 

다음은 지금까지 배운 문제를 토대로
1~4번 중 2개를 합쳐서 풀어보는 5 ~ 6번 문제이다.
9번까지 쭉 뇌를 깨어보는 별 찍기를 해보자.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder str = new StringBuilder();
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if(j < i) {
                    str.append(' ');
                }
                else {
                    str.append('*');
                }
            }
            str.append('\n');
        }

        System.out.println(str);
    }
}
반응형
반응형

 

1번과 비슷한 문제로 별 찍기 1번 문제를 반대로 생각하면 알 수 있다.
 

[ 백준 2438번 문제 ] 별 찍기 - 1 - JAVA

단계적 풀이라는 카테고리를 달고 운영함으로써본래의 의미를 지키기 위해 별 찍기 - 10 문제를 포스팅 하려고 했으나레벨 문제로 존재하기 때문에 1 ~ 10까지 포스팅 해보려고 한다.별 찍기를 통

p-coding.tistory.com

 

문제 핵심

  • 1 <= N <= 100
  • 별을 N부터 1까지 찍어내는 구조

풀이 과정

문제 자체는 어렵지 않아 N부터 1까지 역으로 출력하면 된다.

문제 1번에서 봤던 것과 같이 공백으로 생각하면 이해하기 쉽다.

 

1. N부터 시작해 i가 증감함에 따라 점점 별의 출력 개수를 줄여나가는 방식

for(int i = 0; i < N; i++) {

    for(int j = N - i; j > 0; j--) {
        str.append("*");
    }
    str.append("\n");
}

 

이번에는 직접 이차원 배열을 생성해 칸을 채워 나가는 방법도 시도해 보자.

1번 문제를 반대로만 생각하면 아주 쉽게 풀 수 있는 문제이다.
원래 목표였던 10번 문제 이전까지는 브론즈 문제로 쉽게 풀 수 있다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder str = new StringBuilder();
        int N = Integer.parseInt(br.readLine());

        for(int i = 0; i < N; i++) {

            for(int j = N - i; j > 0; j--) {
                str.append("*");
            }
            str.append("\n");
        }

        System.out.println(str);
    }
}
반응형
반응형

 

이전 별 찍기에서 생각했던 공백을 생각해야 하는 문제가 나왔다.
N * N의 크기로 생각했을 때 공백과 별 위치를 생각하면 풀면 된다.

 

[ 백준 2438번 문제 ] 별 찍기 - 1 - JAVA

단계적 풀이라는 카테고리를 달고 운영함으로써본래의 의미를 지키기 위해 별 찍기 - 10 문제를 포스팅 하려고 했으나레벨 문제로 존재하기 때문에 1 ~ 10까지 포스팅 해보려고 한다.별 찍기를 통

p-coding.tistory.com

 

문제 핵심

  • 1 <= N <= 100
  • N - 1 공백개수를 시작으로 0까지, 별은 1 ~ 5까지 그려나가는 구조

풀이 과정

별 찍기 1에서 사용했던 방식으로 공백과 별을 그려야 하는 조건을 맞추어 코드 구현하면 된다.

1에서는 구조를 설명하기 위해 2차원 배열을 사용하였지만 배열없이 바로 StringBuilder에 값을 추가 하면 된다.

 

1.  N개의 줄을 반복문을 통해 생성

2. 한 줄마다 j가 ( N - i - 1 ) 보다 작을 때 공백 출력, i가 증가함에 따라 공백 감소

3. 아닌 경우에는 별 출력

for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
        if(j < N - i - 1) {
            stringBuilder.append(' ');
        }
        else {
            stringBuilder.append('*');
        }
    }
    stringBuilder.append('\n');
}

아직까지는 괴랄한 별 찍기가 아니라서 괜찮은 것 같다.
이 차원 배열 안에 어떻게 그릴 것인가
그게 중점으로 보인다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if(j < N - i - 1) {
                    stringBuilder.append(' ');
                }
                else {
                    stringBuilder.append('*');
                }
            }
            stringBuilder.append('\n');
        }

        System.out.println(stringBuilder);

    }
}
반응형
반응형

 

이번에는 백준 15652번 문제를 통해 백트래킹 알고리즘 학습을 강화해 보자.
N과 M의 최종문제이다. 지금까지 문제를 생각해보면 이 문제도 15651번 문제 처럼 아주 쉽게 풀 수 있다.

 

문제 핵심

  • 1부터 N까지의 자연수 중 중복 없이 M개를 고른 수열
  • 1 <= M <= N <= 8
  • 중복하여 방문 가능
  • 이전의 수보다 작지만 않으면 됨 ( 같은 수여도 가능 )

풀이 과정

지금까지 풀이 1, 2, 3문제를 보았다면 아주 쉽게 접근할 수 있다.

이전 문제의 이론은? "모든 경로가 중복 방문이 가능하다면? 다시 처음부터 시작하면 된다." 였다.

그렇다면 우리는 해당 숫자부터 즉, 1이면 1부터 2이면 2부터 그대로 값을 전달해주면 된다.

이전 문제에서 고정시켰던 값을 다시 변동 시켜 계속 전달해주면 된다.

핵심 코드를 살펴보자

핵심 코드

다음 반복문에서 i 값을 그대로 전달해주는 것을 알 수 있다.

그렇게 되면 2인 값이 그대로 2로 전달되고 start매개변수를 통해 (M = 3,  N = 3 인 경우) 1, 2, 2 와 같은 값을 얻을 수 있다. 

private static void backTracking(int depth, int M, int N, int start) {
    if (depth == M) {
        for (int i : arr) {
            stringBuilder.append(i).append(" ");
        }
        stringBuilder.append("\n");
        return;
    }

    for (int i = start; i < N; i++) {
        arr[depth] = i + 1;
        backTracking(depth + 1, M, N, i);
    }
}
이제는 정말로 쉽게 풀이될 것이라고 생각한다.
이번 4개의 N과 M의 문제를 통해 충분히 학습될 것이라고 생각한다.
하지만 백트래킹이라고 해서 한 가지 유형만 있는 것은 아니니 몇 개 안남은 단계 문제를 풀고,
이후 다른 백트래킹 문제도 풀어보는 것이 좋겠다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;


public class Main {

    private static int[] arr;
    private static StringBuilder stringBuilder = new StringBuilder();

    private static void backTracking(int depth, int M, int N, int start) {
        if (depth == M) {
            for (int i : arr) {
                stringBuilder.append(i).append(" ");
            }
            stringBuilder.append("\n");
            return;
        }

        for (int i = start; i < N; i++) {
            arr[depth] = i + 1;
            backTracking(depth + 1, M, N, i);
        }
    }


    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        int N = Integer.parseInt(stringTokenizer.nextToken());
        int M = Integer.parseInt(stringTokenizer.nextToken());

        arr = new int[M];


        backTracking(0, M, N, 0);

        System.out.println(stringBuilder);

    }
}
반응형
반응형
이번에는 백준 15651번 문제를 통해 백트래킹 알고리즘 학습을 강화해 보자.
이쯤되면 점점 익숙해질 것이다.

문제 핵심

    • 1부터 N까지의 자연수 중 중복 없이 M개를 고른 수열
    • 1 <= M <= N <= 7
    • 중복하여 방문 가능

풀이 과정

이전 풀이를 보았다면 바로 생각이 날 수도 있다.

모든 경로가 중복 방문이 가능하다면? 다시 처음부터 시작하면 된다.

우리는 무조건 1부터 시작하는 조건을 가지고 있다. 그렇다면 변동하던 시작값을 고정시켜버리면 항상 중복하여 방문하게 된다.

핵심 코드

start 매개변수를 제외 시키고 반복문의 시작값을 0으로 고정하였다.

private static void backTracking(int depth, int M, int N) {
    if (depth == M) {
        for (int i : arr) {
            stringBuilder.append(i).append(" ");
        }
        stringBuilder.append("\n");
        return;
    }

    for (int i = 0; i < N; i++) {
        arr[depth] = i + 1;
        backTracking(depth + 1, M, N);
    }
}

 

 

반복하여 진행하니 점점 한 눈에 알아볼 정도로 난이도가 내려가고 있다. ( 아니면 죄송...)
다음 4번째 N과 M을 끝으로 이해도를 높이길 바란다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    private static int[] arr;
    private static StringBuilder stringBuilder = new StringBuilder();

    private static void backTracking(int depth, int M, int N) {
        if (depth == M) {
            for (int i : arr) {
                stringBuilder.append(i).append(" ");
            }
            stringBuilder.append("\n");
            return;
        }

        for (int i = 0; i < N; i++) {
            arr[depth] = i + 1;
            backTracking(depth + 1, M, N);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        int N = Integer.parseInt(stringTokenizer.nextToken());
        int M = Integer.parseInt(stringTokenizer.nextToken());

        arr = new int[M];


        backTracking(0, M, N);

        System.out.println(stringBuilder);

    }
}
반응형
반응형
요즘 시험이니 일이니 핑계 거리가 생겨 포스팅이 많이 늦어졌습니다. 
다시 매일 노력하여 포스팅 하도록 노력하겠습니다. 감사합니다.

이번에는 백준 15649번 문제를 통해 백트래킹 알고리즘을 실습해 보자. 

백트래킹이란 간단히 설명하면
가능한 모든 경로 탐색 중 조건이 맞지 않으면 이전 단계로 돌아가 다시 탐색하는 알고리즘이다.

 


 

문제 핵심

  • 1부터 N까지의 자연수 중 중복 없이 M개를 고른 수열
  • 1 <= M <= N < 8

풀이 과정

반복과 재귀를 통해 깊이에 따라 값을 처리한다.

dfs를 참고할 수 있겠다.

핵심 코드

  1. 현재 깊이를 체크한다.
    1. 최대 깊이에 도달한다면 리스트 값을 저장하고 리턴한다.
  2. 반복문을 통해 방문되지 않은 리스트 요소를 특정하여 방문한다.
  3. 리스트 현재 깊이 인덱스에 값을 저장한다. 
  4. 재귀를 통해 다음 깊이로 이동한다.
  5. false를 통해 방문을 초기화 하고 이전으로 이동
private static void backTracking(int depth, int M, int N) {
    if(depth == M) {
        for(int i : arr) {
            stringBuilder.append(i).append(" ");
        }
        stringBuilder.append("\n");
        return;
    }

    for(int i = 0; i < N; i++) {
        if(!visited[i]) {
            visited[i] = true;
            arr[depth] = i + 1;
            backTracking(depth + 1, M, N);
            visited[i] = false;
        }
    }
}

EX) N : 4, M : 2

  1. N과 M이 위와 같을 때 1회전의 경우 다음과 같이 진행된다.
  2. 이후 depth + 1을 통해 M과 같아지게 되므로 저장 후 리턴된다.
  3. 마지막 방문했던 인덱스를 false를 통해 이전으로 돌아온다.
    1. 이 때 arr 배열에는 이후 값을 덮어쓰기 때문에 제거할 필요 없다.

 

 

다소 난해하지만, 재귀 방식을 이용한다면 풀 수 있는 문제이다.
이번 풀이에서는 DFS와 비슷하다고 볼 수 있다.
일정 깊이까지 도달한 후 다시 돌아오는 알고리즘으로
디버깅을 통해 로직이 진행되는 순서를 확인하면 좋겠다.

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private static int [] arr;
    private static boolean [] visited;
    private static StringBuilder stringBuilder = new StringBuilder();

    private static void backTracking(int depth, int M, int N) {
        if(depth == M) {
            for(int i : arr) {
                stringBuilder.append(i).append(" ");
            }
            stringBuilder.append("\n");
            return;
        }

        for(int i = 0; i < N; i++) {
            if(!visited[i]) {
                visited[i] = true;
                arr[depth] = i + 1;
                backTracking(depth + 1, M, N);
                visited[i] = false;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());

        arr = new int[M];
        visited = new boolean[N];

        backTracking(0, M, N);

        System.out.println(stringBuilder);
    }
}
반응형
반응형

 

이번 글에서는 백준 26069번 문제를
hashSet를 활용해서 풀어보자

 

 

문제 핵심

  • N : 사람들이 만난 기록 수
  • 최대 길이 20의 문자열인 다른 문자열 A와 B가 공백과 함께 한줄에 주어진다.
  • ChongChong 기록에서 1회 이상 주어짐
  • ChongChong을 만난 사람은 무지개 댄스에 감염
    • ( ChongChong과 chongchong은 다른 이름 )

풀이 과정

ChongChong을 만난 순간 무지개 댄스를 추게 된다.

즉, 무지개 댄스를 한 명이라도 추고 있다면 모두 HashSet에 넣는다.

(Hash)Set에서는 중복값을 제외시켜 저장하기 때문에 모든 입력이 끝난 후  HashSet의 크기를 측정 한다. 

 

핵심 코드

1. 한 줄씩 읽어온다.

2. 두 사람 모두 댄스를 무지개 댄스를 추는지 확인

3. 한 명이라도 춘다면 HashSet에 삽입

        rainbowDanceHumans.add("ChongChong");
        for (int i = 0; i < N; i++) {
           stringTokenizer = new StringTokenizer(bufferedReader.readLine());
           String firstPerson = stringTokenizer.nextToken();
           String secondPerson = stringTokenizer.nextToken();

           if(rainbowDanceHumans.contains(firstPerson) || rainbowDanceHumans.contains(secondPerson)) {
               rainbowDanceHumans.add(firstPerson);
               rainbowDanceHumans.add(secondPerson);
           }
        }

 

Set에 특성만 활용한다면 아주 쉽게 풀 수 있는 문제이다.

(추가) 다들 환절기에 몸 조심 하시길 바랍니다.
두통에 2일 간 작성하지 못했네요..
백준 문제뿐만 아니라 Java class나 다양한 예제로 찾아 뵙겠습니다.

 

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer;
        int N = Integer.parseInt(bufferedReader.readLine());

        HashSet<String> rainbowDanceHumans = new HashSet<>();

        rainbowDanceHumans.add("ChongChong");
        for (int i = 0; i < N; i++) {
           stringTokenizer = new StringTokenizer(bufferedReader.readLine());
           String firstPerson = stringTokenizer.nextToken();
           String secondPerson = stringTokenizer.nextToken();

           if(rainbowDanceHumans.contains(firstPerson) || rainbowDanceHumans.contains(secondPerson)) {
               rainbowDanceHumans.add(firstPerson);
               rainbowDanceHumans.add(secondPerson);
           }
        }

        System.out.println(rainbowDanceHumans.size());

    }
}
반응형
반응형

 

이번 글에서는 큐, 스택에 마무리 문제인 24511번 문제를 해결해 보자.
시간 제한과 메모리 제한이 까다로울 것으로 예상된다.

 

 

문제 핵심

  • 첫째 줄 - 자료구조의 수 : N
  • 둘째 줄 - 수열의 종류 : 0 ( Queue ), 1 ( Stack )
  • 셋째 줄 - 자료구조의 초기값 설정
  • 넷째 줄 - 삽입할 수열의 길이 : M
  • 다섯째 줄 - 삽입할 수열의 원소들

풀이 과정

첫 번째 예제의 과정 중 첫 번째 스텝을 다음과 같이 나타낼 수 있다.

그림 처럼 queue와 stack을 구현하여 값을 삽입하고 제거하는 과정으로 구현해보자. 

아마 메모리에서 먼저 초과되지 않을까 싶다.

 

 

1. 자료구조 저장

0, 1과 구별 값에 따라 큐인지 스택인지 구별하여 저장한다.

List<Object> dataStructure = new ArrayList<Object>();
for (int i = 0; i < N; i++) {
    int type = Integer.parseInt(stringTokenizer.nextToken());

    if (type == 0) {
        dataStructure.add(new LinkedList<Integer>());
    } else {
        dataStructure.add(new Stack<Integer>());
    }

}

 

2. 초기 값 저장

세번 째 줄의 초기 값들을 저장한다.

이 때 초기값들은 instanceof를 통해 자료구조를 판별 후 맞는 메소드를 사용한다.

for (int i = 0; i < N; i++) {
    int num = Integer.parseInt(stringTokenizer.nextToken());
    if (dataStructure.get(i) instanceof Queue) {
        ((Queue<Integer>) dataStructure.get(i)).offer(num);
    } else {
        ((Stack<Integer>) dataStructure.get(i)).add(num);
    }
}

 

3. 메인 과정

새로운 값 들이 큐와 스택을 지나면서 반복되는 과정이다.

이 때, 사실 스택이 값을 거쳐가기만 하기 때문에 의미가 없다.

for (int i = 0; i < M; i++) {
    int num = Integer.parseInt(stringTokenizer.nextToken());
    int temp = num;
    for (int j = 0; j < N; j++) {
        if (dataStructure.get(j) instanceof Queue) {
            ((Queue<Integer>) dataStructure.get(j)).add(temp);
            temp = ((Queue<Integer>) dataStructure.get(j)).remove();
        }
    }

    stringBuilder.append(temp).append(" ");

}

 

 

결과는 시간 초과로 메모리 문제가 아닌 2 중 for문에 N과 M의 최악의 경우 (On2)
100,000 * 100,000 = 10,000,000,000 기 때문에 벌어진 일이다.
그렇다면 2 중 for문의 구조를 제거하고,
스택구조에서 값은 지나치기만 하기 때문에 경우에서 제거한다.

 

4. 자료구조의 재구성

그렇다면 큐의 구조일 때 값을 교체하는 과정이고, 그게 여러개라면 하나씩 밀려나는 과정이다.

큐 여러개가 하나의 값만 가지고 있기 때문에 여러개의 큐가 하나의 큐가 되어버린다.

( 즉, 다음과 같은 구조일 때 새로운 값이 들어온다면 하나의 큐처럼 행동한다. )

그렇다면 하나의 큐를 생성하고 큐일 경우에만 값을 추가한다.

Deque<String> queue = new ArrayDeque<>();
StringBuilder stringBuilder = new StringBuilder();
int N = Integer.parseInt(bufferedReader.readLine());


String[] dataStructureString = bufferedReader.readLine().split(" ");
String[] valueString = bufferedReader.readLine().split(" ");
for (int i = 0; i < N; i++) {
    int type = Integer.parseInt(dataStructureString[i]);
    if(type == 0){
        queue.addLast(valueString[i]);
    }
}

 

5. 메인 과정 재구성

다음과 같이 큐의 삽입과 삭제를 반복하면 O(n)의 경우의 수와 메모리 문제가 모두 해결된다.

int M = Integer.parseInt(bufferedReader.readLine());
String[] addValueString = bufferedReader.readLine().split(" ");

for (int i = 0; i < M; i++) {
    queue.addFirst(addValueString[i]);
    stringBuilder.append(queue.removeLast()).append(" ");
}

 

이번 문제는 마치 알고리즘이 큐처럼 행동하게 하여 해결할 수 있었다.
다음과 같이 자료구조의 개념을 이해한다면 여러방법으로 구현할 수 있다.
줄 서거나(큐), 박스에 물건을 넣고 빼거나(스택) 처럼 한 가지로 제한되지 않는다는 점이다.

시간과 메모리를 줄여야 한다는 점에서 이런 구조를 생각할 수 있었던 문제였다.

 

실패 전체 코드


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        List<Object> dataStructure = new ArrayList<Object>();
        StringTokenizer stringTokenizer;
        StringBuilder stringBuilder = new StringBuilder();
        int N = Integer.parseInt(bufferedReader.readLine());

        stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        for (int i = 0; i < N; i++) {
            int type = Integer.parseInt(stringTokenizer.nextToken());

            if (type == 0) {
                dataStructure.add(new LinkedList<Integer>());
            } else {
                dataStructure.add(new Stack<Integer>());
            }

        }

        stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        for (int i = 0; i < N; i++) {
            int num = Integer.parseInt(stringTokenizer.nextToken());
            if (dataStructure.get(i) instanceof Queue) {
                ((Queue<Integer>) dataStructure.get(i)).offer(num);
            } else {
                ((Stack<Integer>) dataStructure.get(i)).add(num);
            }
        }

        int M = Integer.parseInt(bufferedReader.readLine());

        stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        for (int i = 0; i < M; i++) {
            int num = Integer.parseInt(stringTokenizer.nextToken());
            int temp = num;
            for (int j = 0; j < N; j++) {
                if (dataStructure.get(j) instanceof Queue) {
                    ((Queue<Integer>) dataStructure.get(j)).add(temp);
                    temp = ((Queue<Integer>) dataStructure.get(j)).remove();
                }
            }

            stringBuilder.append(temp).append(" ");

        }

        System.out.println(stringBuilder);
    }
}

성공 전체 코드


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        Deque<String> queue = new ArrayDeque<>();
        StringBuilder stringBuilder = new StringBuilder();
        int N = Integer.parseInt(bufferedReader.readLine());


        String[] dataStructureString = bufferedReader.readLine().split(" ");
        String[] valueString = bufferedReader.readLine().split(" ");
        for (int i = 0; i < N; i++) {
            int type = Integer.parseInt(dataStructureString[i]);
            if(type == 0){
                queue.addLast(valueString[i]);
            }
        }

        int M = Integer.parseInt(bufferedReader.readLine());
        String[] addValueString = bufferedReader.readLine().split(" ");

        for (int i = 0; i < M; i++) {
            queue.addFirst(addValueString[i]);
            stringBuilder.append(queue.removeLast()).append(" ");
        }
        System.out.println(stringBuilder);
    }
}
반응형
반응형
이번 글에서는 백준 2346번 문제를 통해
queue 개념에 관해 좀 더 복잡한 문제를 풀어보자

문제 핵심

  • N : 풍선의 개수 ( 자연수 ) 1 ~ 1000
  • 각 종이에 이동할 숫자가 적혀 있다. ( 0은 없다 )
  • 적힌 종이 별로 양수면 오른쪽, 음수는 왼쪽으로 이동한다.

풀이 과정

다음 Deque를 통해 문제를 풀어 나가며, 인덱스를 기억해 두는 것이 핵심이다.

 

1. 풍선 번호와 종이 저장

1. 큐에 인덱스 값들을 저장한다.

2. move 정수 배열에 해당 종이를 저장한다.

        Deque<Integer> indexQueue = new ArrayDeque<Integer>();

        int[] move = new int[N];
        for (int i = 0; i < N; i++) {
            move[i] = Integer.parseInt(stringTokenizer.nextToken());
            indexQueue.add(i);
        }

 

 

2. 반복

첫 시작은 앞에서부터 시작하기 때문에 미리 처리 한다.

큐에서 꺼낸 값은 인덱스 값이고, 이 인덱스 값을 가지고 move 정수 배열에서 이동할 거리를 확인할 수 있다.

        int removeIndex = indexQueue.removeFirst();
        stringBuilder.append(removeIndex + 1).append(" ");

 

값을 제외한 후에 for문을 통해 값을 원형 큐 처럼 뒤로 보내기 때문에 -1 한다.

ex) 3번 이동해야 할 때, 값을 제거한다면, 값들이 땡겨지기 때문에 2번 이동한다.

 

        while(!indexQueue.isEmpty()) {
            int step = move[removeIndex];

            if(step < 0) {
                for(int j = 0; j < -step - 1; j++) {
                    indexQueue.addFirst(indexQueue.removeLast());
                }
                removeIndex = indexQueue.removeLast();

            } else {
                for(int j = 0; j < step - 1; j++) {
                    indexQueue.addLast(indexQueue.removeFirst());
                }
                removeIndex = indexQueue.removeFirst();
            }
            stringBuilder.append(removeIndex + 1).append(" ");
        }

 

아래의 실패 코드로 이중 리스트 구조로 만들었으나 메모리 초과로 실패하게 되었다.
이 후 불필요한 메모리를 제거하기 위해 분리하여 생성하였고, 성공하였다.

물론 여러 방법 중 하나이니 '틀리다' 라고 말할 수 없겠지만, 
이번 경우는 불필요한 메모리 사용으로 틀렸다고 생각한다.

요즘 컴퓨터 성능은 메모리나 속도면에서 문제 없지만, 막대한 수치가 들어온다면 영향을 끼친다.
때문에 '불필요한' 코드는 줄이도록 하자

실패 코드

다음과 같이 큐 안에 index와 종이의 값들을 모두 넣어서 처리하였으나 과도하게 메모리가 사용되어 메모리 초과되었다.

이후 불필요한 메모리를 제거하기 위해 분리하여 생성하였다.

        Deque<int[]> queue = new LinkedList<>();

 

전체 코드

package org.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(input.readLine());
        StringTokenizer stringTokenizer = new StringTokenizer(input.readLine());
        StringBuilder stringBuilder = new StringBuilder();
        Deque<Integer> indexQueue = new ArrayDeque<Integer>();

        int[] move = new int[N];
        for (int i = 0; i < N; i++) {
            move[i] = Integer.parseInt(stringTokenizer.nextToken());
            indexQueue.add(i);
        }

        int removeIndex = indexQueue.removeFirst();
        stringBuilder.append(removeIndex + 1).append(" ");

        while(!indexQueue.isEmpty()) {
            int step = move[removeIndex];

            if(step < 0) {
                for(int j = 0; j < -step - 1; j++) {
                    indexQueue.addFirst(indexQueue.removeLast());
                }
                removeIndex = indexQueue.removeLast();

            } else {
                for(int j = 0; j < step - 1; j++) {
                    indexQueue.addLast(indexQueue.removeFirst());
                }
                removeIndex = indexQueue.removeFirst();
            }
            stringBuilder.append(removeIndex + 1).append(" ");
        }
        System.out.println(stringBuilder);
    }
}
반응형

+ Recent posts