001) JAVA의 특징

1. 운영체제에 독립적이다.

Java로 작성된 애플리케이션은 JVM 위에서 작동되어 지기 때문에 컴파일러의해 번역된 코드는 플랫폼이 이해하는 코드로 번역되는 것이 아니고, JVM이 해석 가능하도록 번역된다. 그렇기 때문에 어떤 운영체제라도 JVM만 설치되면 자바로 작성된 애플리케이션은 실행이 가능한 독립적인 구조를 갖게 된다.

자바로 작성된 프로그램은 운영체제에 독립적이지만 JVM은 운영체제에 종속적이어서 여러 운영체제에 설치할 수 있는 서로 다른 버전의 JVM을 제공하고 있다.

2. 객체지향언어이다.

자바는 객제지향 프로그래밍 언어로, 객체지향의 특징인 상속, 캡슐화, 다형성이 잘 적용된 언어이다. 그래서 재사용성, 생산성이 높고 유지보수가 우수하다.

상속(Inheritance)

  • 객체를 정의할때 기존에 존재하는 객체의 속성과 기능을 제공받아 정의 하는 것

캡슐화

  • 하나의 클래스 안에 데이터와 기능을 담아 정의하고, 중요한 데이터나 복잡한 기능 등은 숨겨 외부에서 사용할때 필요한 기능만을 제공하는 것

다형성

  • 동일한 메서드를 어떤 객체에 의해서 사용 되냐에 따라 다르게 동작하는 것

3. 자동 메모리 관리(Garbage Collection)

자바로 작성된 프로그램이 실행되면, 가비지컬렉터(garbage collector)가 자동적으로 메모리를 관리해주기 때문에 프로그래머는 메모리를 따로 관리 하지 않아도 된다. 가비지컬렉터가 없다면 프로그래머가 사용하지 않는 메모리를 체크하고 반환하는 일을 수동적으로 처리해야 할 것이다. 자동으로 메모리를 관리한다는 것이 다소 비효율적인 면도 있지만, 프로그래머가 보다 프로그래밍에 집중할 수 있도록 도와준다.

4. 멀티쓰레드를 지원한다.

자바에서 개발된 멀티쓰레드 프로그램은 시스템과 관계없이 구현이 가능하며, 관련된 라이브러리(JAVA API)가 제공되므로 구현이 쉽다.

그리고 여러 쓰레드에 대한 스케줄링(Scheduling)을 자바 인터프리터가 담당하게 된다.

5. 동적 로딩(Dynamic Loading)을 지원한다.

자바로 작성된 애플리케이션은 여러 개의 클래스로 구성되어 있다. 자바는 동적 로딩을 지원하기 때문에 실행 시에 모든 클래스가 로딩되지 않고 필요한 시점에 클래스를 로딩하여 사용할 수 있다는 장점이 있다. 그 외에도 일부 클래스가 변경되어도 전체 애플리케이션을 다시 컴파일 하지 않아도 되며, 애플리케이션의 변경사항이 발생해도 비교적 적은 작업만으로도 처리할 수 있는 유연한 애플리케이션을 작성할 수 있다.

실패율

제출일 : 2021-02-16

문제 풀이 시간 : 45M


Link : https://programmers.co.kr/learn/courses/30/lessons/42889

문제

슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스테이지 차이가 너무 큰 것이 문제였다.

이 문제를 어떻게 할까 고민 한 그녀는 동적으로 게임 시간을 늘려서 난이도를 조절하기로 했다. 역시 슈퍼 개발자라 대부분의 로직은 쉽게 구현했지만, 실패율을 구하는 부분에서 위기에 빠지고 말았다. 오렐리를 위해 실패율을 구하는 코드를 완성하라.

  • 실패율은 다음과 같이 정의한다.
    • 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수

전체 스테이지의 개수 N, 게임을 이용하는 사용자가 현재 멈춰있는 스테이지의 번호가 담긴 배열 stages가 매개변수로 주어질 때, 실패율이 높은 스테이지부터 내림차순으로 스테이지의 번호가 담겨있는 배열을 return 하도록 solution 함수를 완성하라.

제한사항

  • 스테이지의 개수 N은 1 이상 500 이하의 자연수이다.

  • stages의 길이는 1 이상 200,000 이하이다.

  • stages에는 1 이상 N+1 이하의 자연수가 담겨있다.

    • 각 자연수는 사용자가 현재 도전 중인 스테이지의 번호를 나타낸다.
    • 단, N + 1 은 마지막 스테이지(N 번째 스테이지) 까지 클리어 한 사용자를 나타낸다.
  • 만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다.

  • 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다.

예제

입출력 예
N stages result
5 [2, 1, 2, 6, 2, 4, 3, 3] [3,4,2,1,5]
4 [4,4,4,4,4] [4,1,2,3]
입출력 예 설명

입출력 예 #1
1번 스테이지에는 총 8명의 사용자가 도전했으며, 이 중 1명의 사용자가 아직 클리어하지 못했다. 따라서 1번 스테이지의 실패율은 다음과 같다.

  • 1 번 스테이지 실패율 : 1/8

2번 스테이지에는 총 7명의 사용자가 도전했으며, 이 중 3명의 사용자가 아직 클리어하지 못했다. 따라서 2번 스테이지의 실패율은 다음과 같다.

  • 2 번 스테이지 실패율 : 3/7

마찬가지로 나머지 스테이지의 실패율은 다음과 같다.

  • 3 번 스테이지 실패율 : 2/4
  • 4번 스테이지 실패율 : 1/2
  • 5번 스테이지 실패율 : 0/1

각 스테이지의 번호를 실패율의 내림차순으로 정렬하면 다음과 같다.

  • [3,4,2,1,5]

입출력 예 #2

모든 사용자가 마지막 스테이지에 있으므로 4번 스테이지의 실패율은 1이며 나머지 스테이지의 실패율은 0이다.

  • [4,1,2,3]

문제 풀이 접근

  1. 빈도수 계산
  2. 누적합 계산
  3. 실패율 계산
  4. 정렬
  5. 결과 출력

코드

언어 : JAVA

실행시간 :

import java.util.Arrays;

class Node implements Comparable<Node> {
    int num;
    double ratio;

    public Node(int num, double ratio) {
        this.num = num;
        this.ratio = ratio;
    }

    @Override
    public int compareTo(Node o) {
        int res = new Double(o.ratio).compareTo(this.ratio);
        return res == 0 ? this.num - o.num : res;
    }

}

class Solution {
    public static void main(String[] args) {
        int[] ans = solution(5, new int[] { 2, 1, 2, 6, 2, 4, 3, 3 });
        System.out.println(Arrays.toString(ans)); // 3,4,2,1,5
        ans = solution(4, new int[] { 4, 4, 4, 4, 4 });
        System.out.println(Arrays.toString(ans)); // 4,1,2,3
    }

    static int[] solution(int N, int[] stages) {
        // 카운트
        int[] cnt = new int[N + 1];
        for (int i = 0; i < stages.length; i++) {
            cnt[stages[i] - 1]++;
        }

        // 누적합
        int[] sum = cnt.clone();
        for (int i = N - 1; i >= 0; i--) {
            sum[i] += sum[i + 1];
        }

        // 계산
        Node[] stage = new Node[N];
        for (int i = 0; i < stage.length; i++) {
            stage[i] = new Node(i + 1, sum[i] == 0 ? 0 : cnt[i] / (double) sum[i]);
        }

        // 정렬
        Arrays.sort(stage);

        // 결과
        int[] result = new int[N];
        for (int i = 0; i < stage.length; i++) {
            result[i] = stage[i].num;
        }

        return result;
    }
}

7.2 쿼드 트리 뒤집기(ID : QUADTREE)

제출일 : 2021-01-12

문제 풀이 시간 : 1H 30M


Link : https://algospot.com/judge/problem/read/QUADTREE

문제

대량의 좌표 데이터를 메모리 안에 압축해 저장하기 위해 사용하는 여러 기법 중 쿼드 트리(quad tree)란 것이 있습니다. 주어진 공간을 항상 4개로 분할해 재귀적으로 표현하기 때문에 쿼드 트리라는 이름이 붙었는데, 이의 유명한 사용처 중 하나는 검은 색과 흰 색밖에 없는 흑백 그림을 압축해 표현하는 것입니다. 쿼드 트리는 2N × 2N 크기의 흑백 그림을 다음과 같은 과정을 거쳐 문자열로 압축합니다.

  • 이 그림의 모든 픽셀이 검은 색일 경우 이 그림의 쿼드 트리 압축 결과는 그림의 크기에 관계없이 b가 됩니다.
  • 이 그림의 모든 픽셀이 흰 색일 경우 이 그림의 쿼드 트리 압축 결과는 그림의 크기에 관계없이 w가 됩니다.
  • 모든 픽셀이 같은 색이 아니라면, 쿼드 트리는 이 그림을 가로 세로로 각각 2등분해 4개의 조각으로 쪼갠 뒤 각각을 쿼드 트리 압축합니다. 이때 전체 그림의 압축 결과는 x(왼쪽 위 부분의 압축 결과)(오른쪽 위 부분의 압축 결과)(왼쪽 아래 부분의 압축 결과)(오른쪽 아래 부분의 압축 결과)가 됩니다. 예를 들어 그림 (a)의 왼쪽 위 4분면은 xwwwb로 압축됩니다.

그림 (a)와 그림 (b)는 16×16 크기의 예제 그림을 쿼드 트리가 어떻게 분할해 압축하는지를 보여줍니다. 이때 전체 그림의 압축 결과는 xxwww bxwxw bbbww xxxww bbbww wwbb가 됩니다.

쿼드 트리로 압축된 흑백 그림이 주어졌을 때, 이 그림을 상하로 뒤집은 그림 을 쿼드 트리 압축해서 출력하는 프로그램을 작성하세요.

입력

첫 줄에 테스트 케이스의 개수 C (C≤50)가 주어집니다. 그 후 C줄에 하나씩 쿼드 트리로 압축한 그림이 주어집니다. 모든 문자열의 길이는 1,000 이하이며, 원본 그림의 크기는 $2^{20} × 2^{20}$ 을 넘지 않습니다.

출력

각 테스트 케이스당 한 줄에 주어진 그림을 상하로 뒤집은 결과를 쿼드 트리 압축해서 출력합니다.

예제

입력

4
w
xbwwb
xbwxwbbwb
xxwwwbxwxwbbbwwxxxwwbbbwwwwbb

출력

w
xwbbw
xxbwwbbbw
xxwbxwwxbbwwbwbxwbwwxwwwxbbwb

문제 풀이 접근

풀이가 떠오르지 않아 QuadTree 클래스를 만들어 단순하지만 무식한 방법으로 해결하려 접근하였습니다. 하지만 각 부분의 길이가 일정하지 않기 때문에 쪼개기가 까다로웠고 다른 풀이방법을 생각해야 했습니다.

이 문제를 분할하여 상하 반전을 한 값을 다시 병합했을때 결과가 정답이 된다는 것을 확인하고 아래와 같이 코드를 작성하였습니다.

코드

언어 : JAVA

실행 시간 : 156ms

import java.util.Scanner;

public class Main {
    static String str;
    static int pointer;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int C = sc.nextInt();
        for (int tc = 0; tc < C; tc++) {
            str = sc.next();
            pointer = 0;
            System.out.println(reverse());
        }
    }

    private static String reverse() {
        if (str.charAt(pointer) != 'x') {
            return "" + str.charAt(pointer++);
        }
        pointer++;
        String one = reverse();
        String two = reverse();
        String three = reverse();
        String four = reverse();
        return 'x' + three + four + one + two;
    }
}

'Problem' 카테고리의 다른 글

6.8 시계 맞추기 (ID : CLOCKSYNC)  (0) 2021.01.09
6.5 게임판 덮기(ID : BOARDCOVER)  (0) 2021.01.05
6.3 소풍  (0) 2021.01.03

6.8 시계 맞추기 (ID : CLOCKSYNC)

제출일 : 2021-01-09

문제 풀이 시간 : 1H


Link : https://algospot.com/judge/problem/read/CLOCKSYNC

문제

)

그림과 같이 4 x 4 개의 격자 형태로 배치된 16개의 시계가 있다. 이 시계들은 모두 12시, 3시, 6시, 혹은 9시를 가리키고 있다. 이 시계들이 모두 12시를 가리키도록 바꾸고 싶다.

시계의 시간을 조작하는 유일한 방법은 모두 10개 있는 스위치들을 조작하는 것으로, 각 스위치들은 모두 적게는 3개에서 많게는 5개의 시계에 연결되어 있다. 한 스위치를 누를 때마다, 해당 스위치와 연결된 시계들의 시간은 3시간씩 앞으로 움직인다. 스위치들과 그들이 연결된 시계들의 목록은 다음과 같다.

0 0, 1, 2
1 3, 7, 9, 11
2 4, 10, 14, 15
3 0, 4, 5, 6, 7
4 6, 7, 8, 10, 12
5 0, 2, 14, 15
6 3, 14, 15
7 4, 5, 7, 14, 15
8 1, 2, 3, 4, 5
9 3, 4, 5, 9, 13

시계들은 맨 윗줄부터, 왼쪽에서 오른쪽으로 순서대로 번호가 매겨졌다고 가정하자. 시계들이 현재 가리키는 시간들이 주어졌을 때, 모든 시계를 12시로 돌리기 위해 최소한 눌러야 할 스위치의 수를 계산하는 프로그램을 작성하시오.

입력의 첫 줄에는 테스트 케이스의 수 C (C <= 30) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 2개의 정수 H, W (1 <= H,W <= 20) 가 주어집니다. 다음 H 줄에 각 W 글자로 게임판의 모양이 주어집니다. # 은 검은 칸, . 는 흰 칸을 나타냅니다. 입력에 주어지는 게임판에 있는 흰 칸의 수는 50 을 넘지 않습니다.

입력

첫 줄에 테스트 케이스의 개수 C (<= 30) 가 주어진다.
각 테스트 케이스는 한 줄에 16개의 정수로 주어지며, 각 정수는 0번부터 15번까지 각 시계가 가리키고 있는 시간을 12, 3, 6, 9 중 하나로 표현한다.

출력

각 테스트 케이스당 한 줄을 출력한다. 시계들을 모두 12시로 돌려놓기 위해 눌러야 할 스위치의 최소 수를 출력한다. 만약 이것이 불가능할 경우 -1 을 출력한다.

예제

입력

2
12 6 6 6 6 6 12 12 12 12 12 12 12 12 12 12 
12 9 3 12 6 6 9 3 12 9 12 9 12 12 6 6

출력

2
9

문제 풀이 접근

이 문제를 해결하기 위한 중요 아이디어는 같은 스위치를 4번누를 경우와 0번 누르는 경우가 동일하다는것이다. 다시 말하자면 4번 이상 같은 스위치를 누를 필요가 없다는 것을 의미한다.

따라서 위 문제는 4^10가지의 경우의 수를 탐색하여 문제를 해결 할 수 있기에 모든 경우의 수를 탐색하더라도 제한시간내에 문제를 해결할 수 있다.

따라서 재귀함수를 이용하여 문제를 해결 했다.

코드

언어 : JAVA

실행 시간 : 1340ms

import java.util.Scanner;

public class Main {
    static int INF = Integer.MAX_VALUE >> 1, SWITCH = 10, CLOCK = 16;
    static int[][] switches = { { 0, 1, 2 }, { 3, 7, 9, 11 }, { 4, 10, 14, 15 }, { 0, 4, 5, 6, 7 }, { 6, 7, 8, 10, 12 },
            { 0, 2, 14, 15 }, { 3, 14, 15 }, { 4, 5, 7, 14, 15 }, { 1, 2, 3, 4, 5 }, { 3, 4, 5, 9, 13 } };
    static int[] clocks;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int C = sc.nextInt();
        for (int tc = 0; tc < C; tc++) {
            clocks = new int[CLOCK];
            for (int clock = 0; clock < CLOCK; clock++)
                clocks[clock] = (sc.nextInt() / 3) % 4;

            int ret = solve(0);
            System.out.println(ret != INF ? ret : -1);
        }
    }

    private static boolean check() {
        for (int i : clocks)
            if (i != 0)
                return false;
        return true;
    }

    private static void push(int depth) {
        for (int i : switches[depth]) {
            clocks[i]++;
            clocks[i] %= 4;
        }
    }

    private static int solve(int depth) {
        if (depth == SWITCH) {
            return check() ? 0 : INF;
        }

        int ret = INF;
        for (int cnt = 0; cnt < 4; cnt++) {
            ret = Math.min(ret, cnt + solve(depth + 1));
            push(depth);
        }
        return ret;
    }
}

'Problem' 카테고리의 다른 글

7.2 쿼드 트리 뒤집기(ID : QUADTREE)  (0) 2021.01.12
6.5 게임판 덮기(ID : BOARDCOVER)  (0) 2021.01.05
6.3 소풍  (0) 2021.01.03

6.5 게임판 덮기(ID : BOARDCOVER)

제출일 : 2021-01-05

문제 풀이 시간 : 1H


Link : https://www.algospot.com/judge/problem/read/BOARDCOVER

문제

03.png

H*W 크기의 게임판이 있습니다. 게임판은 검은 칸과 흰 칸으로 구성된 격자 모양을 하고 있는데 이 중 모든 흰 칸을 3칸짜리 L자 모양의 블록으로 덮고 싶습니다. 이 때 블록들은 자유롭게 회전해서 놓을 수 있지만, 서로 겹치거나, 검은 칸을 덮거나, 게임판 밖으로 나가서는 안 됩니다. 위 그림은 한 게임판과 이를 덮는 방법을 보여줍니다.

게임판이 주어질 때 이를 덮는 방법의 수를 계산하는 프로그램을 작성하세요.

입력

입력의 첫 줄에는 테스트 케이스의 수 C (C <= 30) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 2개의 정수 H, W (1 <= H,W <= 20) 가 주어집니다. 다음 H 줄에 각 W 글자로 게임판의 모양이 주어집니다. # 은 검은 칸, . 는 흰 칸을 나타냅니다. 입력에 주어지는 게임판에 있는 흰 칸의 수는 50 을 넘지 않습니다.

출력

한 줄에 하나씩 흰 칸을 모두 덮는 방법의 수를 출력합니다.

예제

입력

3 
3 7 
#.....# 
#.....# 
##...## 
3 7 
#.....# 
#.....# 
##..### 
8 10 
########## 
#........# 
#........# 
#........# 
#........# 
#........# 
#........# 
########## 

출력

0
2
1514

문제 풀이 접근

가능한 경우의 수를 재귀함수를 이용하여 구현하였습니다.

예전 N-QUEEN 문제를 풀어봐서 그런지 쉽게 풀수 있었습니다.

왼쪽 위가 0,0이 되도록 하여 블록의 4가지 방향의 상대위치 값을 미리 저장하고. 배열에서 빈 공간을 만났을때 4가지 블록을 비교하여 해당 칸에 블록을 둘 수 있는경우 재귀함수를 호출하도록 문제를 해결하였습니다.

각 메소드명을 기준으로 간단하게 설명을 하면

  • Solve()는 재귀의 메인이 되는 메소드입니다.

  • check(k,i,j)는 현재 위치(i,j)가 빈칸.일 경우에 호출되는 함수로 k번째 블록이 들어갈 수 있는지 확인하는 메소드입니다.

  • isRange(nr,nc)는 (nr, nc)의 값이 보드를 벗어나는지 확인하는 메소드입니다.

  • set(k, i, j, v)는 (i, j)를 기준으로 K번째 블록의 위치 값을 v로 변경하는 메소드입니다. 이 함수를 통해 백트래킹을 쉽게 구현할 수 있습니다.

코드

언어 : JAVA

실행 시간 : 180ms

import java.util.Scanner;

public class Main {
    static int H, W, ans;
    static int[][] map;
    static int[][][] block = { { { 0, 0 }, { 0, 1 }, { 1, 1 } }, { { 0, 0 }, { 0, 1 }, { 1, 0 } },
                              { { 0, 0 }, { 1, 0 }, { 1, 1 } }, { { 0, 0 }, { 1, 0 }, { 1, -1 } }, };

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int C = sc.nextInt();
        for (int tc = 0; tc < C; tc++) {
            H = sc.nextInt();
            W = sc.nextInt();

            map = new int[H][W];
            int cnt = 0;
            for (int i = 0; i < H; i++) {
                String input = sc.next();
                for (int j = 0; j < W; j++) {
                    map[i][j] = input.charAt(j) == '.' ? 0 : 1;
                    if (map[i][j] == 0)
                        cnt++;
                }
            }

            if (cnt % 3 != 0) {
                System.out.println(0);
            } else {
                ans = 0;
                solve(cnt);
                System.out.println(ans);
            }
        }
    }

    private static void solve(int cnt) {
        if (cnt == 0) {
            ans++;
            return;
        }

        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                if (map[i][j] == 0) {
                    for (int k = 0; k < 4; k++) {
                        if (check(k, i, j)) {
                            set(k, i, j, 1);
                            solve(cnt - 3);
                            set(k, i, j, 0);
                        }
                    }
                    return;
                }
            }
        }

    }

    private static void set(int k, int r, int c, int v) {
        for (int i = 0; i < 3; i++) {
            int nr = r + block[k][i][0];
            int nc = c + block[k][i][1];
            map[nr][nc] = v;
        }
    }

    private static boolean check(int k, int r, int c) {
        for (int i = 0; i < 3; i++) {
            int nr = r + block[k][i][0];
            int nc = c + block[k][i][1];
            if (!isRange(nr, nc) || map[nr][nc] == 1) {
                return false;
            }
        }
        return true;
    }

    private static boolean isRange(int nr, int nc) {
        if (0 <= nr && nr < H && 0 <= nc && nc < W)
            return true;
        return false;
    }
}

'Problem' 카테고리의 다른 글

7.2 쿼드 트리 뒤집기(ID : QUADTREE)  (0) 2021.01.12
6.8 시계 맞추기 (ID : CLOCKSYNC)  (0) 2021.01.09
6.3 소풍  (0) 2021.01.03

6.3 소풍

제출일 : 2021-01-03

문제 풀이 시간 : 30M


Link : https://algospot.com/judge/problem/read/PICNIC

문제

안드로메다 유치원 익스프레스반에서는 다음 주에 율동공원으로 소풍을 갑니다. 원석 선생님은 소풍 때 학생들을 두 명씩 짝을 지어 행동하게 하려고 합니다. 그런데 서로 친구가 아닌 학생들끼리 짝을 지어 주면 서로 싸우거나 같이 돌아다니지 않기 때문에, 항상 서로 친구인 학생들끼리만 짝을 지어 줘야 합니다.

각 학생들의 쌍에 대해 이들이 서로 친구인지 여부가 주어질 때, 학생들을 짝지어줄 수 있는 방법의 수를 계산하는 프로그램을 작성하세요. 짝이 되는 학생들이 일부만 다르더라도 다른 방법이라고 봅니다. 예를 들어 다음 두 가지 방법은 서로 다른 방법입니다.

  • (태연,제시카) (써니,티파니) (효연,유리)
  • (태연,제시카) (써니,유리) (효연,티파니)

입력

입력의 첫 줄에는 테스트 케이스의 수 C (C <= 50) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 학생의 수 n (2 <= n <= 10) 과 친구 쌍의 수 m (0 <= m <= n*(n-1)/2) 이 주어집니다. 그 다음 줄에 m 개의 정수 쌍으로 서로 친구인 두 학생의 번호가 주어집니다. 번호는 모두 0 부터 n-1 사이의 정수이고, 같은 쌍은 입력에 두 번 주어지지 않습니다. 학생들의 수는 짝수입니다.

출력

각 테스트 케이스마다 한 줄에 모든 학생을 친구끼리만 짝지어줄 수 있는 방법의 수를 출력합니다.

예제

입력

3 
2 1 
0 1 
4 6 
0 1 1 2 2 3 3 0 0 2 1 3 
6 10 
0 1 0 2 1 2 1 3 1 4 2 3 2 4 3 4 3 5 4 5

출력

1
3
4

문제 풀이 접근

가능한 경우의 수를 재귀함수를 이용하여 구현하였습니다.

A라는 변수를 통해 짝이 맞춰지지 않은 가장 빠른 번호의 학생을 구하고 A번 학생과 짝이 가능하다면 짝을 지어주고 재귀함수를 호출하여 문제를 해결하였습니다.

처음 문제를 읽고 가능한 모든 경우의 수를 파악한 뒤 요구조건에 만족한다면 카운트 하는 방식으로 문제를 해결하려 했습니다. 아래의 소스코드보다 더 많은 변수들이 필요했고 중복을 제거하기 위해 같은 경우지만 다른 경우로 카운트 (1122 == 2211)되는 경우를 제거 해주어야 했습니다. 소스코드가 점점 길어지고 지저분해져 아래와 같이 가능한 경우만 계속 재귀함수를 호출할 수 있도록 코딩하였습니다.

코드

언어 : JAVA

실행 시간 : 176ms

import java.util.Scanner;

public class Main {
    static int N, M, ans;
    static boolean[] visit;
    static int[][] map;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();
        for (int tc = 0; tc < T; tc++) {
            N = sc.nextInt();
            M = sc.nextInt();

            map = new int[N][N];
            for (int i = 0; i < M; i++) {
                int a = sc.nextInt();
                int b = sc.nextInt();
                map[a][b] = map[b][a] = 1;
            }

            ans = 0;
            visit = new boolean[N];
            solve();
            System.out.println(ans);
        }
    }

    private static void solve() {
        int A = -1;
        for (int i = 0; i < N; i++) {
            if (!visit[i]) {
                A = i;
                break;
            }
        }

        if (A == -1) {
            ans++;
            return;
        }

        for (int i = A + 1; i < N; i++) {
            if (!visit[i] && map[A][i] == 1) {
                visit[A] = visit[i] = true;
                solve();
                visit[A] = visit[i] = false;
            }
        }
    }

}

'Problem' 카테고리의 다른 글

7.2 쿼드 트리 뒤집기(ID : QUADTREE)  (0) 2021.01.12
6.8 시계 맞추기 (ID : CLOCKSYNC)  (0) 2021.01.09
6.5 게임판 덮기(ID : BOARDCOVER)  (0) 2021.01.05

[2018 KAKAO] 셔틀버스

제출일 : 2020-08-29

문제 풀이 시간 : 2H 30M


link : https://programmers.co.kr/learn/courses/30/lessons/17678

문제 설명

카카오에서는 무료 셔틀버스를 운행하기 때문에 판교역에서 편하게 사무실로 올 수 있다. 카카오의 직원은 서로를 '크루'라고 부르는데, 아침마다 많은 크루들이 이 셔틀을 이용하여 출근한다.

이 문제에서는 편의를 위해 셔틀은 다음과 같은 규칙으로 운행한다고 가정하자.

  • 셔틀은 09:00부터 총 nt분 간격으로 역에 도착하며, 하나의 셔틀에는 최대 m명의 승객이 탈 수 있다.
  • 셔틀은 도착했을 때 도착한 순간에 대기열에 선 크루까지 포함해서 대기 순서대로 태우고 바로 출발한다. 예를 들어 09:00에 도착한 셔틀은 자리가 있다면 09:00에 줄을 선 크루도 탈 수 있다.

일찍 나와서 셔틀을 기다리는 것이 귀찮았던 콘은, 일주일간의 집요한 관찰 끝에 어떤 크루가 몇 시에 셔틀 대기열에 도착하는지 알아냈다. 콘이 셔틀을 타고 사무실로 갈 수 있는 도착 시각 중 제일 늦은 시각을 구하여라.

단, 콘은 게으르기 때문에 같은 시각에 도착한 크루 중 대기열에서 제일 뒤에 선다. 또한, 모든 크루는 잠을 자야 하므로 23:59에 집에 돌아간다. 따라서 어떤 크루도 다음날 셔틀을 타는 일은 없다.

입력 형식

셔틀 운행 횟수 n, 셔틀 운행 간격 t, 한 셔틀에 탈 수 있는 최대 크루 수 m, 크루가 대기열에 도착하는 시각을 모은 배열 timetable이 입력으로 주어진다.

  • 0 < n ≦ 10
  • 0 < t ≦ 60
  • 0 < m ≦ 45
  • timetable은 최소 길이 1이고 최대 길이 2000인 배열로, 하루 동안 크루가 대기열에 도착하는 시각이 HH:MM 형식으로 이루어져 있다.
  • 크루의 도착 시각 HH:MM00:01에서 23:59 사이이다.

출력 형식

콘이 무사히 셔틀을 타고 사무실로 갈 수 있는 제일 늦은 도착 시각을 출력한다. 도착 시각은 HH:MM 형식이며, 00:00에서 23:59 사이의 값이 될 수 있다.

입출력 예제

n t m timetable answer
1 1 5 [08:00, 08:01, 08:02, 08:03] 09:00
2 10 2 [09:10, 09:09, 08:00] 09:09
2 1 2 [09:00, 09:00, 09:00, 09:00] 08:59
1 1 5 [00:01, 00:01, 00:01, 00:01, 00:01] 00:00
1 1 1 [23:59] 09:00
10 60 45 [23:59,23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59, 23:59] 18:00

문제 풀이 접근

문제를 풀며 꽤나 시간이 많이 걸렸습니다.

처음에 작성한 코드는 주어진 테스트 케이스는 맞지만 체점결과 1개의 케이스가 실패하여 처음부터 코드를 작성하였습니다.

도착시간을 우선순위 큐에 담고 버스가 도착하는 시간에 탑승하는 인원을 확인하고 현재 도착한 셔틀버스를 타기 위한 가장 늦은 시간을 구하는 방식으로 문제를 접근하여 풀었습니다. 22번 테스트케이스가 어떠한 것인지 자꾸 실패하였고 예외를 계속 코딩하다보니 코드가 너무 지저분해지기만 해 코드를 버리고 새로 작성하였습니다.

저는 우선순위큐를 사용했지만 다른 사람들의 풀이를 보니 대부분 String배열을 정렬하여 문제를 해결한것을 보고 나는 왜 이렇게 간단하게 생각하지 못했나 하는 생각을 했습니다.

아래의 코드는 모든 시간에 셔틀버스를 탄 사람들을 각각 다 저장하고 뒤에서부터 탐색하여 빈자리가 있다면 셔틀버스가 오는 시간이 가장 늦은 시간이 되고 빈자리가 없다면 앞사람보다 1분 빨리 도착하는 경우를 구했습니다.

코드

언어 : JAVA

package Programmers.kakao;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class kakao2018_4_셔틀버스 {
    public static void main(String[] args) {
        System.out.println(solution(1, 1, 5, new String[] { "08:00", "08:01", "08:02", "08:03" }));
        System.out.println(solution(2, 10, 2, new String[] { "09:10", "09:09", "08:00" }));
        System.out.println(solution(2, 1, 2, new String[] { "09:00", "09:00", "09:00", "09:00" }));
        System.out.println(solution(1, 1, 5, new String[] { "00:01", "00:01", "00:01", "00:01", "00:01" }));
        System.out.println(solution(1, 1, 1, new String[] { "23:59" }));
        System.out.println(solution(10, 60, 5, new String[] { "23:59", "23:59", "23:59", "23:59", "23:59", "23:59",    "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59", "23:59" }));
    }

    public static String solution(int n, int t, int m, String[] timetable) {

        PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[0] == o2[0])
                    return o1[1] - o2[1];
                return o1[0] - o2[0];
            }
        });
        for (int i = 0; i < timetable.length; i++) {
            StringTokenizer st = new StringTokenizer(timetable[i], ":");
            pq.add(new int[] { Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()) });
        }

        int H = 9, M = 0;
        int[][][] bus = new int[n][m][2];
        int[][] time = new int[n][2];
        for (int k = 0; k < n; k++) {
            time[k][0] = H;
            time[k][1] = M;
            int cnt = 0;
            for (int i = 0; i < m; i++) {
                bus[k][i][0] = -1;
            }
            while (cnt < m && !pq.isEmpty()) {
                int[] now = pq.peek();
                if (now[0] < H || (now[0] == H && now[1] <= M)) {
                    bus[k][cnt] = pq.poll();
                    cnt++;
                } else
                    break;
            }
            // 시간 증가
            H = (M + t >= 60) ? H + 1 : H;
            M = (M + t >= 60) ? M + t - 60 : M + t;
        }

        for (int k = n - 1; k >= 0; k--) {
            for (int i = m - 1; i >= 0; i--) {
                if (bus[k][i][0] == -1)
                    return String.format("%02d:%02d", time[k][0], time[k][1]);

                if (i > 0 && bus[k][i - 1][0] == bus[k][i][0] && bus[k][i - 1][1] == bus[k][i][1])
                    continue;

                if (bus[k][i][1] - 1 < 0)
                    return String.format("%02d:%02d", bus[k][i][0] - 1, 59);
                else
                    return String.format("%02d:%02d", bus[k][i][0], bus[k][i][1] - 1);

            }
        }
        return "";
    }
}

'Problem > Programmers' 카테고리의 다른 글

[2018 KAKAO] 캐시  (0) 2020.08.29
[2018 KAKAO] 다트게임  (0) 2020.08.29
[2018 KAKAO] 비밀지도  (0) 2020.08.29
[카카오 2020 인턴쉽] - 키패드 누르기(JAVA)  (0) 2020.07.27
[Programmers] K번째수 - (Java)  (0) 2020.05.15

[2018 KAKAO] 캐시

제출일 : 2020-08-28

문제 풀이 시간 : 15M


link : https://programmers.co.kr/learn/courses/30/lessons/17680

문제 설명

지도개발팀에서 근무하는 제이지는 지도에서 도시 이름을 검색하면 해당 도시와 관련된 맛집 게시물들을 데이터베이스에서 읽어 보여주는 서비스를 개발하고 있다.
이 프로그램의 테스팅 업무를 담당하고 있는 어피치는 서비스를 오픈하기 전 각 로직에 대한 성능 측정을 수행하였는데, 제이지가 작성한 부분 중 데이터베이스에서 게시물을 가져오는 부분의 실행시간이 너무 오래 걸린다는 것을 알게 되었다.
어피치는 제이지에게 해당 로직을 개선하라고 닦달하기 시작하였고, 제이지는 DB 캐시를 적용하여 성능 개선을 시도하고 있지만 캐시 크기를 얼마로 해야 효율적인지 몰라 난감한 상황이다.

어피치에게 시달리는 제이지를 도와, DB 캐시를 적용할 때 캐시 크기에 따른 실행시간 측정 프로그램을 작성하시오.

입력 형식

  • 캐시 크기(cacheSize)와 도시이름 배열(cities)을 입력받는다.
  • cacheSize는 정수이며, 범위는 0 ≦ cacheSize ≦ 30 이다.
  • cities는 도시 이름으로 이뤄진 문자열 배열로, 최대 도시 수는 100,000개이다.
  • 각 도시 이름은 공백, 숫자, 특수문자 등이 없는 영문자로 구성되며, 대소문자 구분을 하지 않는다. 도시 이름은 최대 20자로 이루어져 있다.

출력 형식

  • 입력된 도시이름 배열을 순서대로 처리할 때, 총 실행시간을 출력한다.

조건

  • 캐시 교체 알고리즘은 LRU(Least Recently Used)를 사용한다.
  • cache hit일 경우 실행시간은 1이다.
  • cache miss일 경우 실행시간은 5이다.

입출력 예제

캐시크기(cacheSize) 도시이름(cities) 실행시간
3 [Jeju, Pangyo, Seoul, NewYork, LA, Jeju, Pangyo, Seoul, NewYork, LA] 50
3 [Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul] 21
2 [Jeju, Pangyo, Seoul, NewYork, LA, SanFrancisco, Seoul, Rome, Paris, Jeju, NewYork, Rome] 60
5 [Jeju, Pangyo, Seoul, NewYork, LA, SanFrancisco, Seoul, Rome, Paris, Jeju, NewYork, Rome] 52
2 [Jeju, Pangyo, NewYork, newyork] 16
0 [Jeju, Pangyo, Seoul, NewYork, LA] 25

문제 풀이 접근

우선 LRU에 대한 개념이 있어야 문제를 해결할 수 있습니다.

여기서 간단하게 설명하자면 LRU는 페이지 교체 알고리즘으로 가장 오랫동안 사용되지 않은 페이지를 제거하는 알고리즘입니다.

저는 이를 큐를 사용하여 구현하였습니다.

최근에 사용되어 값이 큐에 저장되어 있는지 contain()을 이용하여 확인하였고 remove()를 이용하여 값을 제거하고 add()를 사용하여 큐에 가장 마지막 위치에 해당 값을 위치하도록 하였습니다.

이렇게 한다면 큐의 첫번째 값은 가장 오랫동안 사용하지 않은 값이 있게 되며 값이 존재하지 않을때 값을 추가하고 캐시의 크기보다 큐의 크기가 클경우 맨앞의 값을 꺼내왔습니다.

문제를 보면 대소문자를 구분하지 않는다고 명시되어 있습니다. 따라서 모든 도시의 이름을 소문자로 치환하여 문제를 해결하였습니다.

코드

언어 : JAVA

package Programmers.kakao;

import java.util.LinkedList;
import java.util.Queue;

public class kakao2018_3_캐시 {
    public static void main(String[] args) {
        System.out.println(solution(3, new String[] { "Jeju", "Pangyo", "Seoul", "NewYork", "LA", "Jeju", "Pangyo",
                "Seoul", "NewYork", "LA" }));
        System.out.println(solution(3,
                new String[] { "Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul" }));
        System.out.println(solution(2, new String[] { "Jeju", "Pangyo", "Seoul", "NewYork", "LA", "SanFrancisco",
                "Seoul", "Rome", "Paris", "Jeju", "NewYork", "Rome" }));
        System.out.println(solution(5, new String[] { "Jeju", "Pangyo", "Seoul", "NewYork", "LA", "SanFrancisco",
                "Seoul", "Rome", "Paris", "Jeju", "NewYork", "Rome" }));
        System.out.println(solution(2, new String[] { "Jeju", "Pangyo", "NewYork", "newyork" }));
        System.out.println(solution(0, new String[] { "Jeju", "Pangyo", "Seoul", "NewYork", "LA" }));
    }

    public static int solution(int cacheSize, String[] cities) {
        int answer = 0;
        Queue<String> q = new LinkedList<>();

        for (int i = 0; i < cities.length; i++) {
            cities[i] = cities[i].toLowerCase();
        }
        for (int i = 0; i < cities.length; i++) {
            if (q.contains(cities[i])) {
                q.remove(cities[i]);
                q.add(cities[i]);
                answer++;
            } else {
                q.add(cities[i]);
                if (q.size() > cacheSize) {
                    q.poll();
                }
                answer += 5;
            }
        }
        return answer;
    }
}

'Problem > Programmers' 카테고리의 다른 글

[2018 KAKAO] 셔틀버스  (0) 2020.08.30
[2018 KAKAO] 다트게임  (0) 2020.08.29
[2018 KAKAO] 비밀지도  (0) 2020.08.29
[카카오 2020 인턴쉽] - 키패드 누르기(JAVA)  (0) 2020.07.27
[Programmers] K번째수 - (Java)  (0) 2020.05.15