반응형
^ 문자열 시작
$ 문자열 종료
. 임의의 한 문자(단 \은 넣을 수 없음)
* 앞 문자가 없을 수도 무한정 많을 수도 있음
+ 앞 문자가 하나 이상
? 앞 문자가 없거나 하나 있음
[ ]  문자의 집합이나 범위를 나타내며 두 문자 사이는 - 기호로 범위를 나타냅니다. [] 내에서 ^ 가 선행하여 존재하면 not을 나타낸다.
{ }  횟수 또는 범위를 나타냅니다.
( ) 소괄호 안의 문자를 하나의 문자로 인식
| 패턴 안에서 or 연산을 수행할 때 사용
\ 정규 표현식 역슬래시(\)는 확장문자 (역슬래시 다음에 일반 문자가 오면 특수문자로 취급하고 역슬래시 다음에 특수문자가 오면 그 문자 자체를 의미)
\b 단어의 경계
\B 단어가 아닌것에 대한 경계
\A 입력의 시작 부분
\G 이전 매치의 끝
\Z 입력의 끝이지만 종결자가 있는 경우
\z 입력의 끝
\s 공백 문자
\S 공백 문자가 아닌 나머지 문자
\w 알파벳이나 숫자
\W 알파벳이나 숫자를 제외한 문자
\d 숫자 [0-9]와 동일
\D 숫자를 제외한 모든 문자
(?i) 앞 부분에 (?!)라는 옵션을 넣어주게 되면 대소문자는 구분하지 않습니다.

 

응용

[^-_.a-z0-9] 숫자, 알파벳 소문자, -, _, . 을 제외(^)한 케이스
[.]{2,} . 이 여러번 반복되는 케이스
[.]|[.] 처음과 끝에 . 있는 케이스

 

class Solution {
    public String solution(String new_id) {
        String answer = "";
        String temp = new_id.toLowerCase();
        System.out.println(temp);   // ...!@bat#*-.--.y.abcdefghijklm
        temp = temp.replaceAll("[^-_.a-z0-9]", "");
        System.out.println(temp);   // ...bat-.--.y.abcdefghijklm
        temp = temp.replaceAll("[.]{2,}", ".");
        System.out.println(temp);   // .bat-.--.y.abcdefghijklm
        temp = temp.replaceAll("^[.]|[.]$", "");
        System.out.println(temp);   // bat-.--.y.abcdefghijklm
        if (temp.equals(""))
            temp += "a";
        if (temp.length() >= 16) {
            temp = temp.substring(0, 15);
            temp = temp.replaceAll("^[.]|[.]$", "");
        }
        System.out.println(temp);
        if (temp.length() <= 2)
            while (temp.length() < 3)
                temp += temp.charAt(temp.length() - 1);
        System.out.println(temp);

        answer = temp;
        return answer;
    }
}

 

 

 

https://programmers.co.kr/learn/courses/30/lessons/72410

 

코딩테스트 연습 - 신규 아이디 추천

카카오에 입사한 신입 개발자 네오는 "카카오계정개발팀"에 배치되어, 카카오 서비스에 가입하는 유저들의 아이디를 생성하는 업무를 담당하게 되었습니다. "네오"에게 주어진 첫 업무는 새로

programmers.co.kr

 

반응형

'∙Algorithm' 카테고리의 다른 글

[Algorithm] 백준/11657 :: 타임머신  (0) 2019.04.30
[Algorithm] 백준/1026 :: 보물  (0) 2019.04.30
[Algorithm] 백준/2504 :: 괄호의 값  (0) 2019.04.29
[Algorithm] 백준/2493 :: 탑  (0) 2019.04.27
반응형

* 핵심 개념

음수 가중치가 존재하는 경우 최단 거리를 찾기 때문에 다익스트라가 아닌 벨만포드 알고리즘을 사용해야 한다.

방향이 있는 유향그래프이기 때문에 1번 정점에서부터 시작해서

해당 정점을 갈 수 있는 최단 거리와 이전 정점까지 가중치 + 해당 정점 방문에 필요한 가중치를 더해

최소값을 저장해주면 된다.

* 문제

문제

N개의 도시가 있다. 그리고 한 도시에서 출발하여 다른 도시에 도착하는 버스가 M개 있다. 각 버스는 A, B, C로 나타낼 수 있는데, A는 시작도시, B는 도착도시, C는 버스를 타고 이동하는데 걸리는 시간이다. 시간 C가 양수가 아닌 경우가 있다. C = 0인 경우는 순간 이동을 하는 경우, C < 0인 경우는 타임머신으로 시간을 되돌아가는 경우이다.

1번 도시에서 출발해서 나머지 도시로 가는 가장 빠른 시간을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 도시의 개수 N (1 ≤ N ≤ 500), 버스 노선의 개수 M (1 ≤ M ≤ 6,000)이 주어진다. 둘째 줄부터 M개의 줄에는 버스 노선의 정보 A, B, C (1 ≤ A, B ≤ N, -10,000 ≤ C ≤ 10,000)가 주어진다. 

출력

만약 1번 도시에서 출발해 어떤 도시로 가는 과정에서 시간을 무한히 오래 전으로 되돌릴 수 있다면 첫째 줄에 -1을 출력한다. 그렇지 않다면 N-1개 줄에 걸쳐 각 줄에 1번 도시에서 출발해 2번 도시, 3번 도시, ..., N번 도시로 가는 가장 빠른 시간을 순서대로 출력한다. 만약 해당 도시로 가는 경로가 없다면 대신 -1을 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.io.*;
import java.util.*;
 
public class Main {
    static int[] dist = new int[501];
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer stk = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(stk.nextToken());
        int m = Integer.parseInt(stk.nextToken());
        Edge[] edge = new Edge[m + 1];
 
        // 시작점에서 각 정점으로 가는 최단 거리 저장 배열 초기화
        for (int i = 1; i <= n; i++) dist[i] = Integer.MAX_VALUE;
 
        for (int i = 1; i <= m; i++) {
            stk = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(stk.nextToken());
            int v = Integer.parseInt(stk.nextToken());
            int w = Integer.parseInt(stk.nextToken());
            edge[i] = new Edge(u, v, w);
 
        }
        dist[1= 0;        // 1번 정점이 시작점, 시작점까지의 최단거리는 0
        for (int i = 1; i < n; i++) {       // 정점의 수 - 1 번 수행
            for (int j = 1; j <= m; j++) {  // 모든 간선을 사용하여 최단거리가 줄어들면 정보 갱신
                Edge curr = edge[j];
                //u로 가는 최단거리가 바뀌고(무한이 아니고)
                //v로 가는 최단거리 > u까지 필요한 가중치(dist[curr.u]) + u->v 간선 가중치(curr.w)
                if (dist[curr.u] != Integer.MAX_VALUE && dist[curr.v] > dist[curr.u] + curr.w) {
                    dist[curr.v] = dist[curr.u] + curr.w;
                }
            }
        }
 
        // 음수 cycle 확인
        // 만약 음수 cycle이 없다면 시작점에서 모든 점으로 가는 최단거리는 갱신되어 있어야 한다.
        for (int j = 1; j <= m; j++) {
            // 만약 갱신되는 간선이 있다면 음수 cycle 존재
            if (dist[edge[j].u] != Integer.MAX_VALUE && dist[edge[j].v] > dist[edge[j].u] + edge[j].w) {
                bw.write("-1");
                bw.flush();
                bw.close();
                return;
            }
        }
 
        for (int i = 2; i <= n; i++) {
            if (dist[i] != Integer.MAX_VALUE) {
                bw.write(dist[i] + "\n");
            } else {
                bw.write("-1\n");
            }
        }
        bw.flush();
        bw.close();
    }
 
    public static class Edge {
        int u, v, w;
 
        public Edge(int u, int v, int w) {
            this.u = u;
            this.v = v;
            this.w = w;
        }
    }
}
cs


반응형
반응형

* 핵심 개념

최대값은 최소값이랑 곱하고 최소값은 최대값이랑 곱한 값을 더하면 그 값은 최소가 된다.

A,B 배열을 정렬해서 최대값과 최소값을 곱하면서 더하면 된다.

단순 Arrays.sort를 사용해 정렬해 풀 수도 있지만

MergeSort도 연습할겸 구현해서 사용했다.

* 문제

문제

옛날 옛적에 수학이 항상 큰 골칫거리였던 나라가 있었다. 이 나라의 국왕 김지민은 다음과 같은 문제를 내고 큰 상금을 걸었다.

길이가 N인 정수 배열 A와 B가 있다. 다음과 같이 함수 S를 정의하자.

S = A[0]*B[0] + ... + A[N-1]*B[N-1]

S의 값을 가장 작게 만들기 위해 A의 수를 재배열하자. 단, B에 있는 수는 재배열하면 안 된다.

S의 최솟값을 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거나 같은 음이 아닌 정수이다.

출력

첫째 줄에 S의 최솟값을 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import java.io.*;
import java.util.*;
 
public class Main {
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    public static StringTokenizer stk;
 
    public static void main(String[] args) throws Exception {
        int n = Integer.parseInt(br.readLine());
        int[][] num = new int[2][n];
        for (int i = 0; i < 2; i++) {
            stk = new StringTokenizer(br.readLine());
            for (int j = 0; j < n; j++) {
                num[i][j] = Integer.parseInt(stk.nextToken());
            }
            num[i] = merge(num[i], new int[n], 0, n - 1);
        }
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += num[0][i] * num[1][n - i - 1];
        }
        System.out.println(sum);
    }
 
    public static int[] merge(int[] num, int[] tmp, int start, int end) {
        int mid = (start + end) / 2;
        if (start < end) {
            merge(num, tmp, start, mid);
            merge(num, tmp, mid + 1, end);
            num = mergeSort(num, tmp, start, mid, end);
        }
        return num;
    }
 
    public static int[] mergeSort(int[] num, int[] tmp, int start, int mid, int end) {
        for (int i = start; i <= end; i++) {
            tmp[i] = num[i];
        }
        int left = start;
        int right = mid + 1;
        int idx = start;
        while (left <= mid && right <= end) {
            if (tmp[left] <= tmp[right]) {
                num[idx++= tmp[left++];
            } else {
                num[idx++= tmp[right++];
            }
        }
        for (int i = 0; i <= mid - left; i++) {
            num[i + idx] = tmp[i + left];
        }
        return num;
    }
}
cs


반응형
반응형

* 핵심 개념

Stack을 사용해 풀 수 있는 문제다.

다양한 방법이 있지만 필자는 입력받은 문자를 Stack에 넣어가며 값을 비교했다.

Stack에 ()와 [] 짝이 안맞다면 강제로 종료하면 되고,

아니면 ()인 경우 2를, []인 경우 3을 스텍에 넣어준다.

만약, Stack에 [,2,3 이 들어있다면 2+3을 하고 현재 문자가 ] 이라면 *3을 하면 된다.

마지막에 Stack을 돌면서 숫자를 전부 더해주면 된다.


예외 처리는 맨 처음부터 ')'나 ']'가 들어왔을때 처리해야 한다.


* 문제

문제

4개의 기호 ‘(’, ‘)’, ‘[’, ‘]’를 이용해서 만들어지는 괄호열 중에서 올바른 괄호열이란 다음과 같이 정의된다.

  1. 한 쌍의 괄호로만 이루어진 ‘()’와 ‘[]’는 올바른 괄호열이다. 
  2. 만일 X가 올바른 괄호열이면 ‘(X)’이나 ‘[X]’도 모두 올바른 괄호열이 된다. 
  3. X와 Y 모두 올바른 괄호열이라면 이들을 결합한 XY도 올바른 괄호열이 된다.

예를 들어 ‘(()[[]])’나 ‘(())[][]’ 는 올바른 괄호열이지만 ‘([)]’ 나 ‘(()()[]’ 은 모두 올바른 괄호열이 아니다. 우리는 어떤 올바른 괄호열 X에 대하여 그 괄호열의 값(괄호값)을 아래와 같이 정의하고 값(X)로 표시한다. 

  1. ‘()’ 인 괄호열의 값은 2이다.
  2. ‘[]’ 인 괄호열의 값은 3이다.
  3. ‘(X)’ 의 괄호값은 2×값(X) 으로 계산된다.
  4. ‘[X]’ 의 괄호값은 3×값(X) 으로 계산된다.
  5. 올바른 괄호열 X와 Y가 결합된 XY의 괄호값은 값(XY)= 값(X)+값(Y) 로 계산된다.

예를 들어 ‘(()[[]])([])’ 의 괄호값을 구해보자.  ‘()[[]]’ 의 괄호값이 2 + 3×3=11 이므로  ‘(()[[ ]])’의 괄호값은 2×11=22 이다. 그리고  ‘([])’의 값은 2×3=6 이므로 전체 괄호열의 값은 22 + 6 = 28 이다.

여러분이 풀어야 할 문제는 주어진 괄호열을 읽고 그 괄호값을 앞에서 정의한대로 계산하여 출력하는 것이다. 

입력

첫째 줄에 괄호열을 나타내는 문자열(스트링)이 주어진다. 단 그 길이는 1 이상, 30 이하이다.

출력

첫째 줄에 그 괄호열의 값을 나타내는 정수를 출력한다. 만일 입력이 올바르지 못한 괄호열이면 반드시 0을 출력해야 한다. 

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.io.*;
import java.util.*;
 
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = br.readLine();
        Stack<String> stack = new Stack<>();
        int sum = 0;
        String past;
        for (int i = 0; i < input.length(); i++) {
            char ch = input.charAt(i);
            switch (ch) {
                case '(':
                case '[':
                    stack.push(Character.toString(ch));
                    break;
                case ')':
                    check(stack.size());
                    past = stack.pop();
                    if (past.equals("(")) {
                        stack.push(String.valueOf(2));
                    } else if (past.equals("[")) {  //예외 처리
                        System.out.println("0");
                        System.exit(0);
                    } else {  //stack에 숫자가 잇다면
                        int add = Integer.parseInt(past);
                        //숫자라면
                        while (check(stack.size()) && !stack.peek().equals("(")) {
                            String check = stack.pop();
                            if (!check.equals("["&& !check.equals("(")) {
                                add += Integer.parseInt(check);
                            }
                        }
                        stack.pop();
                        stack.push(String.valueOf(add * 2));
                    }
                    break;
                case ']':
                    check(stack.size());
                    past = stack.pop();
                    if (past.equals("[")) {
                        stack.push(String.valueOf(3));
                    } else if (past.equals("(")) {
                        System.out.println("0");
                        System.exit(0);
                    } else {  //stack에 숫자가 잇다면
                        int add = Integer.parseInt(past);
                        while (check(stack.size()) && !stack.peek().equals("[")) {
                            String check = stack.pop();
                            if (!check.equals("["&& !check.equals("(")) {
                                add += Integer.parseInt(check);
                            }
                        }
                        stack.pop();
                        stack.push(String.valueOf(add * 3));
                    }
                    break;
            }
        }
        while (!stack.isEmpty()) {
            try {
                sum += Integer.parseInt(stack.pop());
            } catch (Exception e) {
                sum = 0;
                break;
            }
        }
        System.out.println(sum);
    }
 
    public static boolean check(int size) {
        if (size != 0return true;
        else {
            System.out.println("0");
            System.exit(0);
            return false;
        }
    }
}
cs


반응형
반응형

* 핵심 개념

Stack 자료구조를 할용해 풀 수 있는 문제다. 

1. 처음 Stack에 값을 넣는다. 

2. Stack이 비어있을 때까지 돌면서 자신보다 큰 탑을 찾는다. 

2 -1. 자신보다 큰 값을 찾으면 해당 탑의 idx를 출력 

2-2. 자신보다 큰 값이 없다면 0 출력 

3. Stack에 자신의 값 추가 

2~3 과정을 반복하면 풀 수 있는 문제다.

* 문제 

문제

KOI 통신연구소는 레이저를 이용한 새로운 비밀 통신 시스템 개발을 위한 실험을 하고 있다. 실험을 위하여 일직선 위에 N개의 높이가 서로 다른 탑을 수평 직선의 왼쪽부터 오른쪽 방향으로 차례로 세우고, 각 탑의 꼭대기에 레이저 송신기를 설치하였다. 모든 탑의 레이저 송신기는 레이저 신호를 지표면과 평행하게 수평 직선의 왼쪽 방향으로 발사하고, 탑의 기둥 모두에는 레이저 신호를 수신하는 장치가 설치되어 있다. 하나의 탑에서 발사된 레이저 신호는 가장 먼저 만나는 단 하나의 탑에서만 수신이 가능하다. 

예를 들어 높이가 6, 9, 5, 7, 4인 다섯 개의 탑이 수평 직선에 일렬로 서 있고, 모든 탑에서는 주어진 탑 순서의 반대 방향(왼쪽 방향)으로 동시에 레이저 신호를 발사한다고 하자. 그러면, 높이가 4인 다섯 번째 탑에서 발사한 레이저 신호는 높이가 7인 네 번째 탑이 수신을 하고, 높이가 7인 네 번째 탑의 신호는 높이가 9인 두 번째 탑이, 높이가 5인 세 번째 탑의 신호도 높이가 9인 두 번째 탑이 수신을 한다. 높이가 9인 두 번째 탑과 높이가 6인 첫 번째 탑이 보낸 레이저 신호는 어떤 탑에서도 수신을 하지 못한다.

탑들의 개수 N과 탑들의 높이가 주어질 때, 각각의 탑에서 발사한 레이저 신호를 어느 탑에서 수신하는지를 알아내는 프로그램을 작성하라. 

입력

첫째 줄에 탑의 수를 나타내는 정수 N이 주어진다. N은 1 이상 500,000 이하이다. 둘째 줄에는 N개의 탑들의 높이가 직선상에 놓인 순서대로 하나의 빈칸을 사이에 두고 주어진다. 탑들의 높이는 1 이상 100,000,000 이하의 정수이다.

출력

첫째 줄에 주어진 탑들의 순서대로 각각의 탑들에서 발사한 레이저 신호를 수신한 탑들의 번호를 하나의 빈칸을 사이에 두고 출력한다. 만약 레이저 신호를 수신하는 탑이 존재하지 않으면 0을 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.*;
import java.util.*;
 
public class Main {
    public static StringTokenizer stk;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int n = Integer.parseInt(br.readLine());
        Stack<Pair> stack = new Stack<>();
        stk = new StringTokenizer(br.readLine());
        for (int i = 1; i <= n; i++) {
            int val = Integer.parseInt(stk.nextToken());
            if (stack.isEmpty()) {
                stack.push(new Pair(i, val));
                bw.write("0 ");
                continue;
            }
            while (!stack.isEmpty()) {
                if (stack.peek().val >= val) {  //stack.peek에 부딪히면
                    bw.write(stack.peek().idx + " ");
                    break;
                } else {
                    stack.pop();
                }
            }
            if (stack.isEmpty()) bw.write("0 ");
            stack.push(new Pair(i, val));
        }
        bw.flush();
        bw.close();
    }
 
    public static class Pair {
        int idx, val;
 
        public Pair(int idx, int val) {
            this.idx = idx;
            this.val = val;
        }
    }
}
cs


반응형
반응형

* 핵심 개념

시험 당시에는 17143번 낚시왕 문제보다 복잡해보여서 풀지 않았는데,

다시 풀어보니 역시 풀만한 문제였다. 

특별한 알고리즘 기법이 필요없이 단순히 새로운 크기의 맵을 하나 더 만들어서

새로운 맵에 시뮬레이션한 결과를 저장하고 이를 다시 원래맵에 돌려주기만 하면 된다.

* 문제

문제

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.

공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.

1초 동안 아래 적힌 일이 순서대로 일어난다.

  1. 미세먼지가 확산된다. 확산은 미세먼지가 있는 모든 칸에서 동시에 일어난다.
    • (r, c)에 있는 미세먼지는 인접한 네 방향으로 확산된다.
    • 인접한 방향에 공기청정기가 있거나, 칸이 없으면 그 방향으로는 확산이 일어나지 않는다.
    • 확산되는 양은 Ar,c/5이고 소수점은 버린다.
    • (r, c)에 남은 미세먼지의 양은 Ar,c - (Ar,c/5)×(확산된 방향의 개수) 이다.
  2. 공기청정기가 작동한다.
    • 공기청정기에서는 바람이 나온다.
    • 위쪽 공기청정기의 바람은 반시계방향으로 순환하고, 아래쪽 공기청정기의 바람은 시계방향으로 순환한다.
    • 바람이 불면 미세먼지가 바람의 방향대로 모두 한 칸씩 이동한다.
    • 공기청정기에서 부는 바람은 미세먼지가 없는 바람이고, 공기청정기로 들어간 미세먼지는 모두 정화된다.

공기청정기의 바람은 다음과 같은 방향으로 순환한다.

방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.

입력

첫째 줄에 R, C, T (6 ≤ R, C ≤ 50, 1 ≤ T ≤ 1,000) 가 주어진다.

둘째 줄부터 R개의 줄에 Ar,c (-1 ≤ Ar,c ≤ 1,000)가 주어진다. 공기청정기가 설치된 곳은 Ar,c가 -1이고, 나머지 값은 미세먼지의 양이다. -1은 2번 위아래로 붙어져 있고, 가장 윗 행, 아랫 행과 두 칸이상 떨어져 있다.

출력

첫째 줄에 T초가 지난 후 구사과 방에 남아있는 미세먼지의 양을 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import java.io.*;
import java.util.*;
 
public class Main {
    public static StringTokenizer stk;
    public static Cleaner[] cleaner_pos = new Cleaner[2];   //공기청정기 위치 저장
    public static int r, c, t;
    public static int[][] map;
    public static int[] dx = {1-100};
    public static int[] dy = {001-1};
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        stk = new StringTokenizer(br.readLine());
        r = Integer.parseInt(stk.nextToken());
        c = Integer.parseInt(stk.nextToken());
        t = Integer.parseInt(stk.nextToken());
        map = new int[r][c];
        int idx = 0;
        for (int i = 0; i < r; i++) {
            stk = new StringTokenizer(br.readLine());
            for (int j = 0; j < c; j++) {
                map[i][j] = Integer.parseInt(stk.nextToken());
                if (map[i][j] == -1) {
                    cleaner_pos[idx++= new Cleaner(i, j);
                }
            }
        }
        for (int i = 0; i < t; i++) {
            spreadStart(new int[r][c]);
            cleanerStart(new int[r][c]);
        }
        getAns();
    }
 
    public static void spreadStart(int[][] nmap) {
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                nmap[i][j] += map[i][j];
                if (map[i][j] < 5continue;
                int spreadCnt = map[i][j] / 5;
                for (int k = 0; k < 4; k++) {
                    int ny = i + dy[k];
                    int nx = j + dx[k];
                    //해당 맵에 퍼트릴 수 있는지 확인
                    if (ny >= 0 && ny < r && nx >= 0 && nx < c && map[ny][nx] != -1) {
                        nmap[i][j] -= spreadCnt;
                        nmap[ny][nx] += spreadCnt;
                    }
                }
            }
        }
        spreadCopy(nmap);
    }
 
    public static void cleanerStart(int[][] nmap) {
        for (int idx = 0; idx < 2; idx++) {
            Cleaner curr = cleaner_pos[idx];
            int ny = curr.r;
            int nx = curr.c + 1;
            //오른쪽으로 끝까지
            while (nx < c - 1) {
                nmap[ny][nx + 1= map[ny][nx];
                nx++;
            }
            //상하로 끝까지
            if (idx == 0) {
                while (ny > 0) {
                    nmap[ny - 1][nx] = map[ny][nx];
                    ny--;
                }
            } else {
                while (ny < r - 1) {
                    nmap[ny + 1][nx] = map[ny][nx];
                    ny++;
                }
            }
            //좌측으로 끝까지
            while (nx > 0) {
                nmap[ny][nx - 1= map[ny][nx];
                nx--;
            }
            //공기청정기 위치 전까지
            if (idx == 0) {
                while (ny < curr.r - 1) {
                    nmap[ny + 1][nx] = map[ny][nx];
                    ny++;
                }
            } else {
                while (ny > curr.r + 1) {
                    nmap[ny - 1][nx] = map[ny][nx];
                    ny--;
                }
            }
        }
        cleanerCopy(nmap);
    }
 
    public static void spreadCopy(int[][] nmap) {
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                map[i][j] = nmap[i][j];
            }
        }
    }
 
    public static void cleanerCopy(int[][] nmap) {
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if (i == 0 || i == r - 1 || j == 0 || j == c - 1 || i == cleaner_pos[0].r || i == cleaner_pos[1].r) {
                    map[i][j] = nmap[i][j];
                }
            }
        }
        map[cleaner_pos[0].r][cleaner_pos[0].c] = -1;
        map[cleaner_pos[1].r][cleaner_pos[1].c] = -1;
    }
 
    public static void getAns() {
        int ans = 0;
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if (map[i][j] <= 0continue;
                ans += map[i][j];
            }
        }
        System.out.println(ans);
    }
 
    public static class Cleaner {
        int r, c;
 
        public Cleaner(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }
}
cs


반응형
반응형

* 핵심 개념

처음에는 그냥 우선순위 큐를 두개썻는데 메모리 초과가 낫다.

해결하기 위해 최소 힙, 최대 힙으로 변경했다.

핵심 개념은 최대 힙의 peek는 최소 힙의 peek보다 작거나 같아야 한다.

* 문제

문제

수빈이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 수빈이가 정수를 하나씩 외칠때마다 동생은 지금까지 수빈이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 수빈이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.

예를 들어 수빈이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 수빈이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 수빈이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 수빈이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.

출력

한 줄에 하나씩 N줄에 걸쳐 수빈이의 동생이 말해야하는 수를 순서대로 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.io.*;
import java.util.*;
 
public class Main {
    public static StringTokenizer stk;
    public static StringBuilder sb = new StringBuilder();
    public static PriorityQueue<Integer> minHeap;
    public static PriorityQueue<Integer> maxHeap;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] num = new int[n];
        minHeap = new PriorityQueue<>(Comparator.naturalOrder());
        maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
        for (int i = 0; i < n; i++) {
            num[i] = Integer.parseInt(br.readLine());
            if (i == 0) {
                maxHeap.add(num[i]);
                sb.append(num[i] + "\n");
                continue;
            }
            if (i % 2 == 0) {
                maxHeap.add(num[i]);
            } else {
                minHeap.add(num[i]);
            }
            if (changeCheck()) {
                swap();
            }
            sb.append(maxHeap.peek() + "\n");
        }
        System.out.println(sb);
    }
 
    public static boolean changeCheck() {
        if (minHeap.isEmpty() || maxHeap.isEmpty()) return false;
        return minHeap.peek() <= maxHeap.peek();
    }
 
    public static void swap() {
        int minTomax = minHeap.poll();
        int maxTomin = maxHeap.poll();
        minHeap.add(maxTomin);
        maxHeap.add(minTomax);
    }
}
cs


반응형
반응형

* Review

2019 상반기 공채 오전반 복원문제중 2번문제였다.

기본 삼성유형으로 알려진 BFS, DFS에서 그냥 구현문제가 나올줄은 몰랏지만

쉬웠다는 평이 많은 상반기 코테에서 1솔로 가능할지 의문이다.

* 핵심 개념

이 문제에서는 주의할 점이 두가지 있다.

1. 물고기들 각각을 움직일 때 바로 움직이지 않고, 한번에 움직여야 한다.

필자는 Fish 배열을 만들어 정보를 저장하고 상어 움직임이 끝낫을 때 한번에 이동했다.

물론, 조건에 따라 해당 좌표에 자신보다 작은 상어가 있다면 Fish 배열에 null로 바꿔주면 된다.

2. 시간 속도를 줄이려면 움직여야 하는 거리 % (Width or Depth * 2 - 2) 계산을 하고 움직이면 된다.(584ms -> 308ms)

아쉽게도 시험장에서 30분을 고민하다 이 공식을 못찾았다.

이 두가지 조건만 만족하면 어렵지 않게 풀수있는 기출문제다.

* 문제

문제

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다.

낚시왕은 가장 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.

  1. 낚시왕이 오른쪽으로 한 칸 이동한다.
  2. 낚시왕이 있는 열에 있는 상어 중에서 가장 땅과 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
  3. 상어가 이동한다.

상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계인 경우에는 방향을 반대로 바꿔서 속력을 유지한채로 이동한다.

왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 오른쪽 위에 상어를 구분하기 위해 문자를 적어 놓았다.

상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.

낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.

입력

첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)

둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.

두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.

출력

낚시왕이 잡은 상어 크기의 합을 출력한다.

* 소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import java.io.*;
import java.util.*;
 
public class Main {
    public static StringTokenizer stk;
    public static StringBuilder sb = new StringBuilder();
    public static int[] dy = {-1100};
    public static int[] dx = {001-1};
    public static int width, depth, n, ans = 0;
    public static Fish[] fishInfo = new Fish[10001];
    public static int[][] map;
 
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        stk = new StringTokenizer(br.readLine());
        depth = Integer.parseInt(stk.nextToken());
        width = Integer.parseInt(stk.nextToken());
        n = Integer.parseInt(stk.nextToken());
        map = new int[depth + 1][width + 1];
        for (int i = 1; i <= n; i++) {
            stk = new StringTokenizer(br.readLine());
            int r = Integer.parseInt(stk.nextToken());
            int c = Integer.parseInt(stk.nextToken());
            int s = Integer.parseInt(stk.nextToken());
            int d = Integer.parseInt(stk.nextToken());
            int z = Integer.parseInt(stk.nextToken());
            fishInfo[z] = new Fish(z, c, r, d - 1, s);
            map[r][c] = z;
        }
        for (int i = 1; i <= width; i++) {
            //작살로 물고기 잡음
            for (int j = 1; j <= depth; j++) {
                if (map[j][i] != 0) {
                    fishInfo[map[j][i]] = null;
                    ans += map[j][i];
                    map[j][i] = 0;
                    break;
                }
            }
            //물고기 이동
            for (int j = 1; j <= 10000; j++) {
                if (fishInfo[j] == nullcontinue;
                Fish curr = fishInfo[j];
                int nx = curr.x;
                int ny = curr.y;
                int move = curr.speed;
                int d = curr.d;
                map[ny][nx] = 0;
                switch (d) {    //방향따라 case 다르게
                    //상하
                    case 0:
                    case 1:
                        move %= (depth * 2 - 2);
                        while (move > 0) {
                            if (ny == 1) {
                                d = 1;
                            }
                            if (ny == depth) {
                                d = 0;
                            }
                            ny += dy[d];
                            move--;
                        }
                        fishInfo[curr.idx] = new Fish(curr.idx, nx, ny, d, curr.speed);
                        break;
                    //좌우
                    case 2:
                    case 3:
                        move %= (width * 2 - 2);
                        while (move > 0) {
                            if (nx == 1) d = 2;
                            if (nx == width) d = 3;
                            nx += dx[d];
                            move--;
                        }
                        fishInfo[curr.idx] = new Fish(curr.idx, nx, ny, d, curr.speed);
                        break;
                }
            }
            for (int j = 1; j <= 10000; j++) {
                if (fishInfo[j] == nullcontinue;
                Fish curr = fishInfo[j];
                if (map[curr.y][curr.x] < curr.idx) {   //맵에 저장된 물고기보다 본인이 더 크면
                    fishInfo[map[curr.y][curr.x]] = null;
                    map[curr.y][curr.x] = curr.idx;
                }
            }
        }
        System.out.println(ans);
    }
 
    public static class Fish {
        int idx, x, y, d, speed;
 
        public Fish(int idx, int x, int y, int d, int speed) {
            this.idx = idx;
            this.x = x;
            this.y = y;
            this.d = d;
            this.speed = speed;
        }
    }
}
cs


반응형