문제

시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율

2 초 128 MB 1463 691 581 48.136%

문제

동혁이는 크로스워드 퍼즐을 좋아한다. R×C 크기의 크로스워드 퍼즐을 생각해 보자. 이 퍼즐은 R×C 크기의 표로 이루어지는데, 퍼즐을 다 풀면 금지된 칸을 제외하고는 각 칸에 알파벳이 하나씩 적혀 있게 된다. 아래는 R = 5, C = 5 인 경우 다 푼 퍼즐의 한 예이다. 검은 칸은 금지된 칸이다.

세로 또는 가로로 연속되어 있고, 더 이상 확장될 수 없는 낱말이 퍼즐 내에 존재하는 단어가 된다. 위의 퍼즐과 같은 경우, 가로 낱말은 good, an, messy, it, late의 5개가 있고, 세로 낱말은 game, one, sit, byte의 4개가 있다. 이 중 사전식 순으로 가장 앞서 있는 낱말은 an이다.

다 푼 퍼즐이 주어졌을 때, 퍼즐 내에 존재하는 모든 낱말 중 사전식 순으로 가장 앞서 있는 낱말을 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 퍼즐의 R과 C가 빈 칸을 사이에 두고 주어진다. (2 ≤ R, C ≤ 20) 이어서 R개의 줄에 걸쳐 다 푼 퍼즐이 주어진다. 각 줄은 C개의 알파벳 소문자 또는 금지된 칸을 나타내는 #로 이루어진다. 낱말이 하나 이상 있는 입력만 주어진다.

출력

첫째 줄에 사전식 순으로 가장 앞서 있는 낱말을 출력한다.

풀이

시간복잡도

퍼즐의 크기가 20X20 이하이고, 시간제한이 2초 이므로 시간에 대해서 크게 생각하지 않고 바로구현

  1. #을 만나기전까지는 해당 위치의 문자를 버퍼에 쌓는다.
  2. #을 만난경우 리스트에 문자열을 추가하고 버퍼를 비운다.
  3. #을 만났지만 버퍼 문자열이 비어 있다면 그냥 스킵한다.
  4. 행, 열 모두 1~3의 작업을 수행한다.
  5. 리스트를 정렬하고 가장 첫번째 값이 사전순으로 가장 앞서 있는 낱말이다.

리스트에 추가하는 작업만 수행하므로 LinkedList를 선택했고 ArrayList와 비교해본 결과

LinkedList로 구현한 코드가 조금 더 빨랐다.

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.LinkedList;

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

        String[] size = br.readLine().split(" ");
        int R = Integer.parseInt(size[0]);
        int C = Integer.parseInt(size[1]);
        char[][] array = new char[R][C];
        for (int i = 0; i < R; i++) {
            array[i] = br.readLine().toCharArray();
        }
        LinkedList<String> list = new LinkedList<>();
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < R; i++) {
            buf.setLength(0);
            for (int j = 0; j < C; j++) {
                if (array[i][j] == '#') {
                    if (buf.length() != 0) {
                        if (buf.length() > 1) list.add(buf.toString());
                        buf.setLength(0);
                    }
                } else {
                    buf.append(array[i][j]);
                }
            }
            if (buf.length() > 1) list.add(buf.toString());
        }
        for (int i = 0; i < C; i++) {
            buf.setLength(0);
            for (int j = 0; j < R; j++) {
                if (array[j][i] == '#') {
                    if (buf.length() != 0) {
                        if (buf.length() > 1) list.add(buf.toString());
                        buf.setLength(0);
                    }
                } else {
                    buf.append(array[j][i]);
                }
            }
            if (buf.length() > 1)
                list.add(buf.toString());
        }

        Collections.sort(list);
        System.out.println(list.get(0));
    }
}

문제

시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율

1 초 512 MB 22928 8320 5196 32.708%

문제

섬으로 이루어진 나라가 있고, 모든 섬을 다리로 연결하려고 한다. 이 나라의 지도는 N×M 크기의 이차원 격자로 나타낼 수 있고, 격자의 각 칸은 땅이거나 바다이다.

섬은 연결된 땅이 상하좌우로 붙어있는 덩어리를 말하고, 아래 그림은 네 개의 섬으로 이루어진 나라이다. 색칠되어있는 칸은 땅이다.

다리는 바다에만 건설할 수 있고, 다리의 길이는 다리가 격자에서 차지하는 칸의 수이다. 다리를 연결해서 모든 섬을 연결하려고 한다. 섬 A에서 다리를 통해 섬 B로 갈 수 있을 때, 섬 A와 B를 연결되었다고 한다. 다리의 양 끝은 섬과 인접한 바다 위에 있어야 하고, 한 다리의 방향이 중간에 바뀌면 안된다. 또, 다리의 길이는 2 이상이어야 한다.

다리의 방향이 중간에 바뀌면 안되기 때문에, 다리의 방향은 가로 또는 세로가 될 수 밖에 없다. 방향이 가로인 다리는 다리의 양 끝이 가로 방향으로 섬과 인접해야 하고, 방향이 세로인 다리는 다리의 양 끝이 세로 방향으로 섬과 인접해야 한다.

섬 A와 B를 연결하는 다리가 중간에 섬 C와 인접한 바다를 지나가는 경우에 섬 C는 A, B와 연결되어있는 것이 아니다.

아래 그림은 섬을 모두 연결하는 올바른 2가지 방법이고, 다리는 회색으로 색칠되어 있다. 섬은 정수, 다리는 알파벳 대문자로 구분했다.

다리가 교차하는 경우가 있을 수도 있다. 교차하는 다리의 길이를 계산할 때는 각 칸이 각 다리의 길이에 모두 포함되어야 한다. 아래는 다리가 교차하는 경우와 기타 다른 경우에 대한 2가지 예시이다.

나라의 정보가 주어졌을 때, 모든 섬을 연결하는 다리 길이의 최솟값을 구해보자.

입력

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.

출력

모든 섬을 연결하는 다리 길이의 최솟값을 출력한다. 모든 섬을 연결하는 것이 불가능하면 -1을 출력한다.

제한

  • 1 ≤ N, M ≤ 10
  • 3 ≤ N×M ≤ 100
  • 2 ≤ 섬의 개수 ≤ 6

풀이

문제요약

  1. 모든 섬을 연결하는 다리 길이의 최솟값을 구해야 함
  2. 다리의 방향은 변경될 수 없고, 길이는 2개 이상이어야 한다.
  3. 상하좌우로 붙어있다면 같은 섬이다.
  4. 섬의 경우 1, 바다의 경우 0으로 입력이 주어진다.

접근 아이디어

  1. 각 섬들별로 식별가능한 인덱스 부여 (BFS 탐색)
  2. 다리를 놓을 수 있는 모든 경우 탐색 (완전탐색)
  3. 연결 가능한 간선의 최소값 구하기 (최소 스패닝 트리 - 크루스칼)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int[] dx = new int[] {-1,1,0,0};
    static int[] dy = new int[] {0,0,-1,1};
    static ArrayList<int[]> bridges = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int answer = 0;
        String[] input = br.readLine().split(" ");

        int N = Integer.parseInt(input[0]);
        int M = Integer.parseInt(input[1]);
        int[][] graph = new int[N][M];
        boolean[][] visited = new boolean[N][M];
        for (int i = 0; i < N; i++) {
            String[] inputs = br.readLine().split(" ");
            for (int j = 0; j < M; j++) {
                graph[i][j] = Integer.parseInt(inputs[j]);
            }
        }
        int islandIndex = 1;

        ArrayList<ArrayList<int[]>> lists = new ArrayList<>();
        for (int i = 0; i <= 6; i++) { // 섬의 개수가 6개 이하이므로 6개만 만들면 댐
            lists.add(new ArrayList<int[]>());
        }

        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (!visited[i][j] && graph[i][j] == 1) {
                    Queue<int[]> queue = new LinkedList<>();
                    queue.add(new int[] {i,j});
                    visited[i][j] = true;
                    graph[i][j] = islandIndex;
                    lists.get(islandIndex).add(new int[]{i,j});
                    while (!queue.isEmpty()) {
                        int[] value = queue.poll();
                        for (int k = 0; k < dx.length; k++) {
                            int cy = value[0] + dy[k];
                            int cx = value[1] + dx[k];

                            if (cx < 0 || cx >= M || cy < 0 || cy >= N) continue;
                            if (visited[cy][cx] || graph[cy][cx] == 0) continue;
                            int[] newVal = new int[]{cy,cx};
                            queue.add(newVal);
                            graph[cy][cx] = islandIndex;
                            lists.get(islandIndex).add(newVal);
                            visited[cy][cx] = true;
                        }
                    }
                    islandIndex++;
                }
            }
        }

//        // bridge에 현재값, 타겟값, 거리
        for (int i = 0; i < lists.size(); i++) {
            ArrayList<int[]> islands = lists.get(i);
            for (int j = 0; j < islands.size(); j++) {
                int[] island = islands.get(j);
                for (int k = island[0]-1; k > 0; k--) { // 위쪽 탐색
                    if (graph[k][island[1]] == graph[island[0]][island[1]])
                        break;
                    if (graph[k][island[1]] != 0) { // 0 이 아니고, 현재 값과 다르다면
                        if (island[0] - k == 2)
                            break;
                        int[] bridge = new int[3];
                        bridge[0] = graph[island[0]][island[1]];
                        bridge[1] = graph[k][island[1]];
                        bridge[2] = island[0] - k - 1;
                        bridges.add(bridge);
                        break;
                    }
                }
                for (int k = island[0]+1; k < N; k++) { // 아래쪽 탐색
                    if (graph[k][island[1]] == graph[island[0]][island[1]])
                        break;
                    if (graph[k][island[1]] != 0) { // 0 이 아니고, 현재 값과 다르다면
                        if (k - island[0] == 2)
                            break;
                        int[] bridge = new int[3];
                        bridge[0] = graph[island[0]][island[1]];
                        bridge[1] = graph[k][island[1]];
                        bridge[2] = k - island[0] - 1;
                        bridges.add(bridge);
                        break;
                    }
                }
                for (int k = island[1]-1; k > 0; k--) { // 왼쪽 탐색

                    if (graph[island[0]][k] == graph[island[0]][island[1]])
                        break;
                    if (graph[island[0]][k] != 0) { // 0 이 아니고, 현재 값과 다르다면
                        if (island[1] - k == 2) 
                            break;
                        int[] bridge = new int[3];
                        bridge[0] = graph[island[0]][island[1]];
                        bridge[1] = graph[island[0]][k];
                        bridge[2] = island[1] - k - 1;
                        bridges.add(bridge);
                        break;
                    }
                }
                for (int k = island[1]+1; k < M; k++) { // 오른쪽 탐색

                    if (graph[island[0]][k] == graph[island[0]][island[1]])
                        break;
                    if (graph[island[0]][k] != 0) { // 0 이 아니고, 현재 값과 다르다면
                        if (k - island[1] == 2)
                            break;
                        int[] bridge = new int[3];
                        bridge[0] = graph[island[0]][island[1]];
                        bridge[1] = graph[island[0]][k];
                        bridge[2] = k - island[1] - 1;
                        bridges.add(bridge);
                        break;
                    }
                }
            }
        }
        // 간선의 값을 기준으로 연결 시키기
        Collections.sort(bridges, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[2] - o2[2];
            }
        });
        int[] arr = new int[islandIndex];
        for (int i = 1; i < arr.length; i++) {
            arr[i] = i;
        }
        for (int i = 0; i < bridges.size(); i++) {
            int[] bridge = bridges.get(i);
            int a = find(arr, bridge[0]);
            int b = find(arr, bridge[1]);
            if (a == b) continue;
            union(arr, a, b);
            answer += bridge[2];
        }
        int parent = find(arr, arr[1]);
        for (int i = 1; i < arr.length; i++) {
            if (find(arr, i) != parent) {
                answer = -1;
                break;
            }
        }
        if (answer == 0)
            answer = -1;
        System.out.println(answer);
    }
    public static int find(int[] array, int x) {
        // 내 루트노드 찾기
        if(array[x] == x) return x;
        return array[x] = find(array, array[x]);
    }
    public static void union(int[] array, int x, int y) {
        int a = find(array, x);
        int b = find(array, y);
        if(a==b)return;
        array[b] = a;
    }
}

문제

유명한 제빵사 김원웅은 빵집을 운영하고 있다. 원웅이의 빵집은 글로벌 재정 위기를 피해가지 못했고, 결국 심각한 재정 위기에 빠졌다.

원웅이는 지출을 줄이고자 여기저기 지출을 살펴보던 중에, 가스비가 제일 크다는 것을 알게되었다. 따라서 원웅이는 근처 빵집의 가스관에 몰래 파이프를 설치해 훔쳐서 사용하기로 했다.

빵집이 있는 곳은 R*C 격자로 표현할 수 있다. 첫째 열은 근처 빵집의 가스관이고, 마지막 열은 원웅이의 빵집이다.

원웅이는 가스관과 빵집을 연결하는 파이프를 설치하려고 한다. 빵집과 가스관 사이에는 건물이 있을 수도 있다. 건물이 있는 경우에는 파이프를 놓을 수 없다.

가스관과 빵집을 연결하는 모든 파이프라인은 첫째 열에서 시작해야 하고, 마지막 열에서 끝나야 한다. 각 칸은 오른쪽, 오른쪽 위 대각선, 오른쪽 아래 대각선으로 연결할 수 있고, 각 칸의 중심끼리 연결하는 것이다.

원웅이는 가스를 되도록 많이 훔치려고 한다. 따라서, 가스관과 빵집을 연결하는 파이프라인을 여러 개 설치할 것이다. 이 경로는 겹칠 수 없고, 서로 접할 수도 없다. 즉, 각 칸을 지나는 파이프는 하나이어야 한다.

원웅이 빵집의 모습이 주어졌을 때, 원웅이가 설치할 수 있는 가스관과 빵집을 연결하는 파이프라인의 최대 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 R과 C가 주어진다. (1 ≤ R ≤ 10,000, 5 ≤ C ≤ 500)

다음 R개 줄에는 빵집 근처의 모습이 주어진다. '.'는 빈 칸이고, 'x'는 건물이다. 처음과 마지막 열은 항상 비어있다.

출력

첫째 줄에 원웅이가 놓을 수 있는 파이프라인의 최대 개수를 출력한다.

풀이

선택 알고리즘

DFS : R*C 배열이 주어졌을 때, i,0 인덱스가 근처 빵집이고, i,C 인덱스가 원웅이의 빵집이다. 따라서, i,0부터 i,C 까지 이동할 수 있는 모든 경우를 탐색하기 때문에 DFS를 선택했다.

시간 복잡도

R개의 경우의수가 있고, depth가 C가 될때까지 반복하며, 3개의 방향으로 탐색

= 3RC

풀이

  1. 근처 빵집에서 원웅이 빵집까지 이동할 수 있는 방법은 오른쪽 위 대각선, 오른쪽, 오른쪽 아래 대각선 으로 세가지 경우가 있다. 따라서 오른쪽으로 한칸 이동 시 마다 세가지의 경우로 탐색을 시도한다.
  2. 이미 이동했던 경로는 다시 이동할 수 없기 때문에 방문 배열을 생성하여 관리 해준다.
  3. 세가지 이동 경우 중 그림을 그려 봤을 때 최대한 위쪽에 붙어서 이동해야 다음 이동 시에 갈 수 있는 경우를 최대로 할 수 있을 것이라고 생각함.

코드

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

public class Main {
    static int R;
    static int C;
    static char[][] graph;
    static boolean[][] visited;
    static int answer = 0;
    static boolean flag = false;
    static int[] dy = new int[] {-1, 0, 1};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String[] size = br.readLine().split(" ");

        R = Integer.parseInt(size[0]);
        C = Integer.parseInt(size[1]);

        graph = new char[R][C];
        visited = new boolean[R][C];
        for (int i = 0; i < R; i++) {
            graph[i] = br.readLine().toCharArray();
        }

        for (int i = 0; i < R; i++) {
            visited[i][0] = true; // 0번 부터 시작
            dfs(i, 0,0); // 도달 가능한지 탐색
            flag = false; // 플래그 초기화
        }
        System.out.println(answer);
    }
    public static void dfs(int y, int x, int depth) {
        if (depth == C-1) {
            answer++; // 끝까지 도달했다면 답 1추가
            flag = true; // 끝까지 도달했으므로 더이상 탐색하지 말고 돌아오도록 플래그 설정
            return;
        }

        for (int i = 0; i < dy.length; i++) {
            if (flag) // 플래그 설정되었다면 더이상 탐색하지 않고 돌아와
                break;
            int currentX = x + 1; 
            int currentY = y + dy[i]; // 3방향으로 탐색

            if (currentY < 0 || currentY >= R) continue;
            if (visited[currentY][currentX] || graph[currentY][currentX] == 'x') continue;
            visited[currentY][currentX] = true;
            dfs(currentY, currentX, depth + 1);
        }
    }
}
문제

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다.

오늘부터 인구 이동이 시작되는 날이다.

인구 이동은 하루 동안 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다.

  • 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면, 두 나라가 공유하는 국경선을 오늘 하루 동안 연다.
  • 위의 조건에 의해 열어야하는 국경선이 모두 열렸다면, 인구 이동을 시작한다.
  • 국경선이 열려있어 인접한 칸만을 이용해 이동할 수 있으면, 그 나라를 오늘 하루 동안은 연합이라고 한다.
  • 연합을 이루고 있는 각 칸의 인구수는 (연합의 인구수) / (연합을 이루고 있는 칸의 개수)가 된다. 편의상 소수점은 버린다.
  • 연합을 해체하고, 모든 국경선을 닫는다.

각 나라의 인구수가 주어졌을 때, 인구 이동이 며칠 동안 발생하는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N, L, R이 주어진다. (1 ≤ N ≤ 50, 1 ≤ L ≤ R ≤ 100)

둘째 줄부터 N개의 줄에 각 나라의 인구수가 주어진다. r행 c열에 주어지는 정수는 A[r][c]의 값이다. (0 ≤ A[r][c] ≤ 100)

인구 이동이 발생하는 일수가 2,000번 보다 작거나 같은 입력만 주어진다.

출력

인구 이동이 며칠 동안 발생하는지 첫째 줄에 출력한다.

풀이

선택 알고리즘

BFS - 국경선을 이을 수 있는지 여부는 2차원배열의 상하좌우로 탐색하는 방식에 유리한 BFS를 선정함

시간 복잡도

전체 후보를 모두 방문해야 하고, NxN 배열을 방문하므로 N제곱 X N제곱 (BFS)

N의 네제곱이므로, 50 X 50 X 50 X 50 = 6,250,000으로 계산

구현

  1. 모든 땅을 방문하여, 국경선을 열 수 있는 경우, 국경선을 공유 가능한 모든 땅의 좌표를 arrayList에 담아서 보관하고, 탐색이 끝났다면 큐에 보관한 어레이리스트를 저장 → 인구 이동이 일어나는 경우가 하루에 여러 땅에서 일어날 수 있기 때문에 각각 관리해줘야 한다.
  2. 큐가 비어있지 않다면 어레이리스트를 꺼내서 국경선을 공유하는 모든 땅의 값을 업데이트 해줌
  3. 만약 그 어디도 방문하지 못했다면 (국경선을 공유할 수 있는 땅이 없다면), 종료한다.

코드

package com.company.baekjoon;

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

public class BaekJoon16234 {
    static int N;
    static int L;
    static int R;
    static int[][] arr;
    static boolean[][] union;
    static Queue<int[]> queue;
    static Queue<ArrayList<int[]>> a = new LinkedList<>();
    static ArrayList<int[]> arrayList = new ArrayList<>();
    static int[] dx = new int[] { -1, 1, 0, 0};
    static int[] dy = new int[] { 0, 0, -1, 1};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        L = Integer.parseInt(st.nextToken());
        R = Integer.parseInt(st.nextToken());
        int answer = 0;
        arr = new int[N][N];
        union = new boolean[N][N];
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < N; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        queue = new LinkedList<>();

        while (true) {
           for (boolean booleans[]: union) {
                Arrays.fill(booleans, false);
            }
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (!union[i][j]) {
                        queue.add(new int[]{i,j});
                        bfs();
                        if (arrayList.size() > 0) {
                            a.add((ArrayList<int[]>) arrayList.clone());
                            arrayList.clear();
                        }
                    }
                }
            }
            while (!a.isEmpty()) {
                ArrayList<int[]> list = a.poll();

                int size = list.size();
                int sum = 0;

                if (size == 0) { // 인구이동 후보가 없음
                    break;
                }

                for (int k = 0; k < size; k++) {
                    int[] n = list.get(k);
                    sum += arr[n[0]][n[1]];
                }
                int value = sum / size;
                for (int k = 0; k < size; k++) {
                    int[] n = list.get(k);
                    arr[n[0]][n[1]] = value;
                }
            }

            arrayList.clear();

            // 만약 더이상 진행할 수 없을 경우 (아무 지역도 후보가 될 수 없는 경우)
            boolean isContinue = false;
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (union[i][j])
                        isContinue = true;
                }
            }
            if (!isContinue)
                break;

            // 모든 나라 검사 다 했으면 1 증가함.
            answer++;

        }
        System.out.println(answer);
    }
    public static void bfs() {
        while (!queue.isEmpty()) {
            int[] nation = queue.poll();
            for (int i = 0; i < dx.length; i++) {
                int currentX = nation[0] + dx[i];
                int currentY = nation[1] + dy[i];

                if (currentX < 0 || currentX >= N || currentY < 0 || currentY >= N) continue;
                if (union[currentX][currentY]) continue; // 이미 방문한경우
                if (Math.abs(arr[nation[0]][nation[1]] - arr[currentX][currentY]) >= L &&
                        Math.abs(arr[nation[0]][nation[1]] - arr[currentX][currentY]) <= R) { // 국경이 열림
                    if (!union[nation[0]][nation[1]]) {
                        union[nation[0]][nation[1]] = true;
                        arrayList.add(new int[]{nation[0], nation[1]});
                    }
                    union[currentX][currentY] = true;
                    queue.add(new int[]{currentX, currentY});
                    arrayList.add(new int[]{currentX, currentY});
                }
            }
        }
    }
}

 

Android 장치에 블루투스 마우스 장치를 연결하면 화면에 마우스 커서가 표시됩니다.

이 커서를 Android 7.0 이상부터 커서를 숨기거나, 모양을 바꿀 수 있게 되었습니다.

필자의 경우 마우스 커서를 숨기는 기능에 사용했었는데, 이때 사용한 코드를 공유합니다.

블루투스 마우스 커서의 경우 setPointerIcon 메서드를 호출한 뷰 계층에서는 마우스 커서 모양이 변경되는것으로 보이며,

시스템 UI위에서는 기본 마우스 커서가 보이게 됩니다.

아래는 제가 사용했던 코드 일부를 공유합니다.
@Override
public boolean dispatchGenericMotionEvent(MotionEvent motionEvent) {
    int index = motionEvent.getActionIndex();

    if (motionEvent.getToolType(index) == MotionEvent.TOOL_TYPE_MOUSE) {
        if (rootLayout != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            PointerIcon pointerIcon = PointerIcon.getSystemIcon(this, -1);
            rootLayout.setPointerIcon(pointerIcon);
        }
    }
    return super.dispatchGenericMotionEvent(motionEvent);
}

 

  • 부족한 금액 계산하기

문제 설명

새로 생긴 놀이기구는 인기가 매우 많아 줄이 끊이질 않습니다. 이 놀이기구의 원래 이용료는 price원 인데, 놀이기구를 N 번 째 이용한다면 원래 이용료의 N배를 받기로 하였습니다. 즉, 처음 이용료가 100이었다면 2번째에는 200, 3번째에는 300으로 요금이 인상됩니다.
놀이기구를 count번 타게 되면 현재 자신이 가지고 있는 금액에서 얼마가 모자라는지를 return 하도록 solution 함수를 완성하세요.
단, 금액이 부족하지 않으면 0을 return 하세요.

제한사항

  • 놀이기구의 이용료 price : 1 ≤ price ≤ 2,500, price는 자연수
  • 처음 가지고 있던 금액 money : 1 ≤ money ≤ 1,000,000,000, money는 자연수
  • 놀이기구의 이용 횟수 count : 1 ≤ count ≤ 2,500, count는 자연수

입출력 예

pricemoneycountresult

3 20 4 10

입출력 예 설명

입출력 예 #1
이용금액이 3인 놀이기구를 4번 타고 싶은 고객이 현재 가진 금액이 20이라면, 총 필요한 놀이기구의 이용 금액은 30 (= 3+6+9+12) 이 되어 10만큼 부족하므로 10을 return 합니다.

참고 사항

  • 미션 언어는 Java, JavaScript, Python3, C++ 만 해당 됩니다.
  • 같은 코드를 제출한 사람이 여럿이라면 코드를 가장 먼저 제출한 분께 상품을 드립니다.
  • 좋아요 수가 동일할 경우 코드를 가장 먼저 제출한 분께 상품을 드립니다.

 

나의 풀이

 

문제는 간단했는데, 네가지 테스트가 계속 실패하는 바람에.. 도무지 모르겠어서 구글링 했더니 money값을 받을 때 

int형이 아닌 long형으로 받아야 한다고 해서 매개변수 타입을 long으로 변경하니 성공했다.. 문제를 보면 알 수 있는 부분인데 좀더 문제를 정확히 읽고 풀어야겠다 ㅠ-ㅠ

    public long solution(int price, long money, int count) {
        for(int i = 1; i <= count; i++)  
            money = money - price * i;
        return  money > 0 ? 0 : money*-1;
    }

문제 설명

당신은 폰켓몬을 잡기 위한 오랜 여행 끝에, 홍 박사님의 연구실에 도착했습니다. 홍 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다.
홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다. 예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다. 이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다.

  1. 첫 번째(3번), 두 번째(1번) 폰켓몬을 선택
  2. 첫 번째(3번), 세 번째(2번) 폰켓몬을 선택
  3. 첫 번째(3번), 네 번째(3번) 폰켓몬을 선택
  4. 두 번째(1번), 세 번째(2번) 폰켓몬을 선택
  5. 두 번째(1번), 네 번째(3번) 폰켓몬을 선택
  6. 세 번째(2번), 네 번째(3번) 폰켓몬을 선택

이때, 첫 번째(3번) 폰켓몬과 네 번째(3번) 폰켓몬을 선택하는 방법은 한 종류(3번 폰켓몬 두 마리)의 폰켓몬만 가질 수 있지만, 다른 방법들은 모두 두 종류의 폰켓몬을 가질 수 있습니다. 따라서 위 예시에서 가질 수 있는 폰켓몬 종류 수의 최댓값은 2가 됩니다.
당신은 최대한 다양한 종류의 폰켓몬을 가지길 원하기 때문에, 최대한 많은 종류의 폰켓몬을 포함해서 N/2마리를 선택하려 합니다. N마리 폰켓몬의 종류 번호가 담긴 배열 nums가 매개변수로 주어질 때, N/2마리의 폰켓몬을 선택하는 방법 중, 가장 많은 종류의 폰켓몬을 선택하는 방법을 찾아, 그때의 폰켓몬 종류 번호의 개수를 return 하도록 solution 함수를 완성해주세요.

제한사항

  • nums는 폰켓몬의 종류 번호가 담긴 1차원 배열입니다.
  • nums의 길이(N)는 1 이상 10,000 이하의 자연수이며, 항상 짝수로 주어집니다.
  • 폰켓몬의 종류 번호는 1 이상 200,000 이하의 자연수로 나타냅니다.
  • 가장 많은 종류의 폰켓몬을 선택하는 방법이 여러 가지인 경우에도, 선택할 수 있는 폰켓몬 종류 개수의 최댓값 하나만 return 하면 됩니다.

입출력 예

numsresult

[3,1,2,3] 2
[3,3,3,2,2,4] 3
[3,3,3,2,2,2] 2

입출력 예 설명

입출력 예 #1
문제의 예시와 같습니다.

입출력 예 #2
6마리의 폰켓몬이 있으므로, 3마리의 폰켓몬을 골라야 합니다.
가장 많은 종류의 폰켓몬을 고르기 위해서는 3번 폰켓몬 한 마리, 2번 폰켓몬 한 마리, 4번 폰켓몬 한 마리를 고르면 되며, 따라서 3을 return 합니다.

입출력 예 #3
6마리의 폰켓몬이 있으므로, 3마리의 폰켓몬을 골라야 합니다.
가장 많은 종류의 폰켓몬을 고르기 위해서는 3번 폰켓몬 한 마리와 2번 폰켓몬 두 마리를 고르거나, 혹은 3번 폰켓몬 두 마리와 3번 폰켓몬 한 마리를 고르면 됩니다. 따라서 최대 고를 수 있는 폰켓몬 종류의 수는 2입니다.

 

1. 최대한 많은 수의 포켓몬을 골라야 하기 때문에, 중복을 제거해준다.
2. 가질 수 있는 최댓값은 N/2 마리 이므로, 배열의 길이 / 2 가 최대값이다.
3. 중복을 제거한 포켓몬 수 보다 최댓값이 크면 중복을 제거한 포켓몬 수가 최대값이 된다.

 

풀이 코드

  public int solution(int[] nums) {
        int answer = nums.length / 2;

        Set<Integer> set = new HashSet<>();

        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
        }
        if(answer > set.size())
            answer = set.size();
        return answer;
    }

 

오늘은 오준석님의 생존코딩 강의를 듣던 중 함수와 인터페이스의 색상을 구분하는 테마를 사용하고 계셔서

이참에 테마를 변경 했습니다.

 

적용하고나니 더 코드 읽기가 좋아진 것 같네요 ㅎㅎ

 

바로 본문으로 이동 하겠습니다.

 

안드로이드 스튜디오 테마 변경 방법

 

File > Settings > Appearance & Behavior > Appearance 이동 후 Theme 선택 해주시면 됩니다.

 

별도의 테마를 설치하지 않으신 분은 저처럼 테마가 여러개 나오지 않으실 겁니다. 

 

외부 테마를 사용하는 방법

 

Files > Settings > Plugins > "Material Theme UI" 검색

 

이 플러그인 설치 후 IDE를 재시작 하시면 위의 테마를 선택하는 부분에서 마음에 드는 테마를 선택하시면 됩니다.

 

제가 사용하는 Atom One Dark 테마는 인터페이스와 클래스를 구분하여 하이라이트 해주기 때문에 코드 읽기가 더 편한것 같아서 추천 드립니다!

 

이상으로 글 마치겠습니다!

문제 설명

0과 1로 이루어진 어떤 문자열 x에 대한 이진 변환을 다음과 같이 정의합니다.

  1. x의 모든 0을 제거합니다.
  2. x의 길이를 c라고 하면, x를 "c를 2진법으로 표현한 문자열"로 바꿉니다.

예를 들어, x = "0111010"이라면, x에 이진 변환을 가하면 x = "0111010" -> "1111" -> "100" 이 됩니다.

0과 1로 이루어진 문자열 s가 매개변수로 주어집니다. s가 "1"이 될 때까지 계속해서 s에 이진 변환을 가했을 때, 이진 변환의 횟수와 변환 과정에서 제거된 모든 0의 개수를 각각 배열에 담아 return 하도록 solution 함수를 완성해주세요.


제한사항

  • s의 길이는 1 이상 150,000 이하입니다.
  • s에는 '1'이 최소 하나 이상 포함되어 있습니다.

입출력 예

sresult

"110010101001" [3,8]
"01110" [3,3]
"1111111" [4,1]

입출력 예 설명

입출력 예 #1

  • "110010101001"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.

회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과

1 "110010101001" 6 6 "110"
2 "110" 1 2 "10"
3 "10" 1 1 "1"
  • 3번의 이진 변환을 하는 동안 8개의 0을 제거했으므로, [3,8]을 return 해야 합니다.

입출력 예 #2

  • "01110"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.

회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과

1 "01110" 2 3 "11"
2 "11" 0 2 "10"
3 "10" 1 1 "1"
  • 3번의 이진 변환을 하는 동안 3개의 0을 제거했으므로, [3,3]을 return 해야 합니다.

입출력 예 #3

  • "1111111"이 "1"이 될 때까지 이진 변환을 가하는 과정은 다음과 같습니다.

회차이진 변환 이전제거할 0의 개수0 제거 후 길이이진 변환 결과

1 "1111111" 0 7 "111"
2 "111" 0 3 "11"
3 "11" 0 2 "10"
4 "10" 1 1 "1"
  • 4번의 이진 변환을 하는 동안 1개의 0을 제거했으므로, [4,1]을 return 해야 합니다.

나의 풀이

1. 문자열에서 0 제거하기

2. 이진 변환하기

3. 문자열의 길이가 1이 될때까지 반복하기

 

public int[] solution(String s) {
        int[] answer = new int[2];
        int zeroCount = 0;
        int binaryCount = 0;
        while (true) {

            if (s.length() == 1) { // 문자열의 길이가 1일 경우 break
                break;
            }

            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == '0') {
                    zeroCount++; // 문자가 0일경우 count 증가
                }
            }

            s = s.replaceAll("0", ""); // 0을 모두 공백으로 변경

            int binaryStr = s.length();

            s = Integer.toBinaryString(binaryStr); // 문자열의 길이를 이진수로 변환
            binaryCount++;
        }
        
        answer[0] = binaryCount;
        answer[1] = zeroCount;

        return answer;
    }

문제 설명

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다.

각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 조각으로 만들 수 있는 소수가 몇 개인지 return 하도록 solution 함수를 완성해주세요.

제한사항

  • numbers는 길이 1 이상 7 이하인 문자열입니다.
  • numbers는 0~9까지 숫자만으로 이루어져 있습니다.
  • "013"은 0, 1, 3 숫자가 적힌 종이 조각이 흩어져있다는 의미입니다.

입출력 예

numbersreturn

"17" 3
"011" 2

입출력 예 설명

예제 #1
[1, 7]으로는 소수 [7, 17, 71]를 만들 수 있습니다.

예제 #2
[0, 1, 1]으로는 소수 [11, 101]를 만들 수 있습니다.

  • 11과 011은 같은 숫자로 취급합니다.

출처

 

나의 풀이

1. 만들 수 있는 모든 경우의 수 구하기 - DFS 이용

2. 중복 제거하기 및 0으로 시작하는 숫자는 지우기.

3. 소수 찾기

 

public class FindDecimal {
	// 모든 경우의 수를 담을 어레이리스트
    ArrayList<String> arrayList = new ArrayList<>();
    
    public int solution(String numbers) {
    
        int answer = 0;
        // dfs에서 방문확인
        boolean[] booleans = new boolean[numbers.length()];
        // 소수를 찾을 리스트
        ArrayList<String> answerList = new ArrayList<>();
        
        char[] chars = numbers.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            String s = "";
            dfs(i, booleans, s, chars);
        }
		
        // 0으로 시작하는 문자열은 삭제시키고 0부터 다시 시작
        for (int i = 0; i < arrayList.size(); i++) {
            if(arrayList.get(i).startsWith("0")) {
                arrayList.remove(i);
                i = -1;
            }
            else if (!answerList.contains(arrayList.get(i))) {
                answerList.add(arrayList.get(i));
            }
        }
        
        // 인덱스에 해당하는 숫자가 소수일 경우 정답 수 증가
        for (int i = 0; i < answerList.size(); i++) {
            int n = Integer.parseInt(answerList.get(i));

            for(int j = 2; j <= n; j++) {
                if(j == n) {
                    answer++;
                }
                if ( n%j == 0) {
                    break;
                }

            }
        }
        
        // System.out.println(answer);
        
        return answer;
    }
    
    // dfs 함수
    public void dfs(int i, boolean[] booleans, String s, char[] chars) {
        booleans[i] = true;
        s = s + chars[i];
        arrayList.add(s);
        for (int j = 0; j < booleans.length; j++) {
            if (!booleans[j]) {
                dfs(j, booleans, s, chars);
            }

        }
        booleans[i] = false;
    }

    public static void main(String[] args) {
        FindDecimal findDecimal = new FindDecimal();
        findDecimal.solution("17");
        // System.out.println(findDecimal.arrayList);

    }

}

 

알고리즘이 약하다는 생각에 대학생 취준 이후로 다시 알고리즘 공부를 시작하려고 한다. 더 좋은 방법이 있으면 댓글 달아주세요 ㅎㅅㅎ  dfs 알고리즘 짜는데 시간이 좀 걸려서 한시간 정도 걸렸다.... 공부하자!!

 

+ Recent posts