14425번: 문자열 집합

첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다.  다음 N개의 줄에는 집합 S에 포함되어 있는 문자열들이 주어진다. 다음 M개의 줄에는 검사해야 하는 문자열들이 주어

www.acmicpc.net

 

Language: Java

 

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.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
 
public class Main {
 
    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 st = new StringTokenizer(br.readLine());
        int num1 = Integer.parseInt(st.nextToken());
        int num2 = Integer.parseInt(st.nextToken());
 
        String[] sArr1 = new String[num1];
        for (int i = 0; i < num1; i++) {
            sArr1[i] = br.readLine();
        }
 
        int cnt = 0;
        for (int i = 0; i < num2; i++) {
            cnt += check(sArr1, br.readLine());
        }
 
        bw.write(cnt + "");
        bw.flush();
        bw.close();
    }
 
    public static int check(String[] sArr1, String s) {
        int cnt = 0;
 
        for (int i = 0; i < sArr1.length; i++) {
            if (sArr1[i].equals(s)) {
                cnt++;
            }
        }
 
        return cnt;
 
    }
 
}
 
 
 

🤔 해설

1. M개의 문자열

    - String 배열에 저장

2. 집합 S

    - 집합 S를 위한 배열을 생성하지 않고, 입력마다 check()을 호출하여 M개의 문자열과 같은 단어인지 확인

 

😮 이 외의 풀이

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
 
public class Main {
 
    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 st = new StringTokenizer(br.readLine());
        int num1 = Integer.parseInt(st.nextToken());
        int num2 = Integer.parseInt(st.nextToken());
 
        Map<String, Integer> map = new HashMap<>();
        for (int i = 0; i < num1; i++) {
            map.put(br.readLine(), 0);
        }
 
        int cnt = 0;
        for (int i = 0; i < num2; i++) {
            if(map.containsKey(br.readLine())) {
                cnt++;
            }
        }
 
        bw.write(cnt + "");
        bw.flush();
        bw.close();
    }
 
}
 
 
 

1. HashMap

    - Map에 M개의 문자열 저장

2. containsKey()

    - 집합 S의 값을 HashMap의 Key값과 비교

 

🤓 집합과 맵으로 분류된 문제인데, 속도 차이가 6배정도 난다..!

- 제출번호 64906951: check() 사용

- 제출번호 64907853: HashMap<>() 사용

 

⭐ Hash Table은 검색, 삽입, 삭제가 모두 평균적으로 1의 시간 복잡도를 갖을 정도로 빠름

 

 

 

🔗 소스 코드
HJ0216/TIL/BOJ

 

📚 참고 자료

 

[백준] 14425번 : 문자열 집합 – JAVA [자바]

https://www.acmicpc.net/problem/14425 14425번: 문자열 집합 첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다. 다음 N개의 줄에는 집합 S에 포함되어 있는 문자열들이 주어진다. 다

propercoding.tistory.com

 

 

10815번: 숫자 카드

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,

www.acmicpc.net

 

Language: Java

 

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int num1 = Integer.parseInt(br.readLine());
 
        String[] sArr1 = new String[num1];
        StringTokenizer st1 = new StringTokenizer(br.readLine());
        for (int i = 0; i < num1; i++) {
            sArr1[i] = st1.nextToken();
        }
        
        int num2 = Integer.parseInt(br.readLine());
 
        String[] sArr2 = new String[num2];
        StringTokenizer st2 = new StringTokenizer(br.readLine());
        for (int i = 0; i < num2; i++) {
            sArr2[i] = st2.nextToken();
        }
        
        for(int i=0; i<num2; i++) {
            int j = 0;
            for(j=0; j<num1; j++) {
                if(sArr2[i].equals(sArr1[j])) {
                    bw.write("1 ");
                    break;
                }
            }
            if(j==num1) {
                bw.write("0 ");
            }
        }
        
        bw.flush();
        bw.close();
    }
 
}
 
 
 

🚨 이중 for문에 의해서 시간복잡도가 n^2까지 커질 수 있어 시간 초과

 

😮 이 외의 풀이

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int num1 = Integer.parseInt(br.readLine());
 
        int[] iArr1 = new int[num1];
        StringTokenizer st1 = new StringTokenizer(br.readLine());
        for (int i = 0; i < num1; i++) {
            iArr1[i] = Integer.parseInt(st1.nextToken());
        }
 
        Arrays.sort(iArr1);
 
        int num2 = Integer.parseInt(br.readLine());
 
        StringTokenizer st2 = new StringTokenizer(br.readLine());
        for (int i = 0; i < num2; i++) {
            bw.write(bSearch(iArr1, Integer.parseInt(st2.nextToken())) + " ");
        }
 
        bw.flush();
        bw.close();
    }
 
    public static int bSearch(int[] iArr1, int search) {
        int first = 0;
        int last = iArr1.length - 1;
 
        while (first <= last) {
            int mid = (first + last) / 2;
 
            if (iArr1[mid] == search) {
                return 1;
            }
 
            if (iArr1[mid] < search) {
                first = mid + 1;
            } else {
                last = mid - 1;
            }
        }
 
        return 0;
 
    }
 
}
 
 
 

- 이진 탐색

  ⭐ 이진 탐색 대상은 전제 조건으로 정렬되어 있어야 함

    - 상근이가 갖고 있는지 확인해야 할 카드 값을 search로 받아서 상근이의 카드 배열 iArr1과 비교

    - 예시

        - 상근이가 갖고 있는 카드: 0 1 2 3 4 5 6 7 8 9

        - search = 6, first = 0, last = 9, mid = 4

        - search가 더 크므로 시작값을 0 ▶ 5으로 변경

        - search = 6, first = 5, last = 9, mid = 7

        - search가 더 작으므로 끝 값을 9 ▶ 6으로 변경

        - search와 mid가 동일하므로 return 1

 

 

 

🔗 소스 코드
HJ0216/TIL/BOJ

 

📚 참고 자료

 

[BOJ] 백준 10815번 : 숫자 카드 (JAVA)

문제의 링크 : https://www.acmicpc.net/problem/10815 10815번: 숫자 카드 첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진

steady-coding.tistory.com

 

 

1735번: 분수 합

첫째 줄과 둘째 줄에, 각 분수의 분자와 분모를 뜻하는 두 개의 자연수가 순서대로 주어진다. 입력되는 네 자연수는 모두 30,000 이하이다.

www.acmicpc.net

 

Language: Java

 

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
 
public class Main {
 
    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 st1 = new StringTokenizer(br.readLine(), " ");
        double top1 = Integer.parseInt(st1.nextToken());
        double bottom1 = Integer.parseInt(st1.nextToken());
 
        StringTokenizer st2 = new StringTokenizer(br.readLine(), " ");
        double top2 = Integer.parseInt(st2.nextToken());
        double bottom2 = Integer.parseInt(st2.nextToken());
 
        double top = 1;
        double bottom = 0;
        Loop: for (double i = 1; i <= bottom2; i++) {
            for (double j = 1; j <= bottom1; j++) {
                if (bottom1 * i == bottom2 * j) {
                    bottom = bottom1 * i;
                    top = top2 * j + top1 * i;
                    break Loop;
                }
            }
        }
 
        for (double k = 2; k <= (top >= bottom ? top : bottom); k++) {
            if (top % k == 0 && bottom % k == 0) {
                top /= k;
                bottom /= k;
            }
        }
 
        bw.write((int)top + " " + (int)bottom);
 
        bw.flush();
        bw.close();
    }
 
}
 
 
 

🚨 입력값이 30,000일 때 top, bottom값을 구하기까지의 2중 for문에서 시간 초과 발생

    - 시간 복잡도: O(n^2)

 

😮 이 외의 풀이

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
 
public class Main {
 
    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 st1 = new StringTokenizer(br.readLine(), " ");
        int top1 = Integer.parseInt(st1.nextToken());
        int bottom1 = Integer.parseInt(st1.nextToken());
 
        StringTokenizer st2 = new StringTokenizer(br.readLine(), " ");
        int top2 = Integer.parseInt(st2.nextToken());
        int bottom2 = Integer.parseInt(st2.nextToken());
 
        int top = top1 * bottom2 + top2 * bottom1;
        int bottom = bottom1 * bottom2;
 
        int gdc = getGCD(top, bottom);
 
        bw.write((top/gdc) + " " + (bottom/gdc));
 
        bw.flush();
        bw.close();
    }
    
    public static int getGCD(int p, int q) {
        return q == 0 ? p : getGCD(q, p%q);
    }
 
}
 
 
 

- 유클리드 호제법

    -  2개의 자연수의 최대공약수를 구하는 알고리즘

    - 2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같음
    - p를 q로 나누어 떨어지면 q가 최대 공약수, 나누어 떨이지지 않으면 p를 q로 나눈 나머지에 대해서 getGCD 수행

    - 예시: 36, 27

        - 36은 27로 나누어 떨어지지 않으므로 27과 9에 대해서 getGCD 실행

        - 27은 9로 나누어 떨어지므로 9가 36과 27의 최대 공약수

 

 

 

🔗 소스 코드
HJ0216/TIL/BOJ

 

📚 참고 자료

 

[Algorithm] 유클리드 호제법(최대공약수 구하기) 공부

정의

seunghyum.github.io

 

 

11651번: 좌표 정렬하기 2

첫째 줄에 점의 개수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N개의 줄에는 i번점의 위치 xi와 yi가 주어진다. (-100,000 ≤ xi, yi ≤ 100,000) 좌표는 항상 정수이고, 위치가 같은 두 점은 없다.

www.acmicpc.net

 

Language: Java

 

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int num = Integer.parseInt(br.readLine());
 
        int[][] intArrXY = new int[num][2];
 
        for (int i = 0; i < num; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine(), " ");
 
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
 
            intArrXY[i][0= a;
            intArrXY[i][1= b;
 
        }
 
        Arrays.sort(intArrXY, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1!= o2[1] ? o1[1- o2[1] : o1[0- o2[0];
            }
        });
 
        for (int i = 0; i < num; i++) {
            bw.write(intArrXY[i][0+ " " + intArrXY[i][1+ "\n");
        }
 
        bw.flush();
        bw.close();
    }
 
}
 
 
 

🤔 해설

1. sort()

    - 이중 배열의 경우, 기존 sort 메서드를 통해 정렬할 수 없으므로 정렬 기준을 오버라이딩하여 이차원 배열 정렬

2. @Override

    - Comparator 클래스에서 compare 메서드 Override

    - 배열의 두번째 요소가 다르면 두번째 요소로 정렬, 같으면 첫 번째 요소로 정렬

    - 예시

        - 입력값: (3, 4), (1, 1), (1, -1)

        - intArr[0][0] = 3, intArr[0][1] = 4

        - intArr[1][0] = 1, intArr[1][1] = 1

        - intArr[2][0] = 1, intArr[2][1] = -1

        - intArr = {{3, 4}, {1, 1}, {1, -1}}

        - int[] o1 = {3, 4}, int[] o2 = {1, 1}

        - int[0] o1 = 3, int[0] o2 = 1

        - int[0] o1 - int[0] o2 : 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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int num = Integer.parseInt(br.readLine());
 
        int[][] intArrXY = new int[num][2];
 
        for (int i = 0; i < num; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine(), " ");
 
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
 
            intArrXY[i][0= a;
            intArrXY[i][1= b;
 
        }
 
        Arrays.sort(intArrXY, (arr1, arr2) -> {
            if (arr1[1== arr2[1]) {
                return arr1[0- arr2[0];
            } else {
                return arr1[1- arr2[1];
            }
        });
 
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            sb.append(intArrXY[i][0+ " " + intArrXY[i][1+ "\n");
        }
 
        bw.write(sb + "");
        bw.flush();
        bw.close();
    }
 
}
 
 
 

1. 람다식(익명 클래스)를 Comparator 클래스 대신 사용

2. StringBuffer 사용

 

⭐ 메서드 사용 방법을 자세히 알고 싶으면, Eclipse 기준 ctrl + method 클릭

1
2
3
4
5
6
7
8
9
10
11
    public static <T> void sort(T[] a, Comparator<super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null00);
        }
    }
 
 
 

- sort 사용 시, 첫 번째 인자가 T[]이므로 T는 int[]

 

 

 

🔗 소스 코드
HJ0216/TIL/BOJ

 

 

2231번: 분해합

어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다. 예를 들어, 245의 분해합은 256(=245+2+4+5)이

www.acmicpc.net

 

Language: Java

 

🚨 고민해보다 푸는 방법을 도저히 모르겠어서, 풀이를 찾아 봄

 

😮 찾아본 풀이

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        int N = Integer.parseInt(br.readLine());
 
        int i = 0;
        for (i = 0; i < N; i++) {
            int num = i;
            int sum = 0;
 
            while (num != 0) {
                sum += num % 10;
                num /= 10;
            }
 
            if ((sum + i) == N) {
                bw.write(i + "");
                break;
            }
        }
 
        if (i == N) {
            bw.write("0");
        }
        bw.flush();
        bw.close();
 
    }
 
}
 
 
 

1. while 반복문

    - num: 생성자

    - sum: 생성자 각 자리의 합

  ⭐ sum을 구하기 위해 생성자 역할을 하는 i 이외에도 i와 동일한 값을 갖는 num 선언

2. if 조건문

    - 분해합이 입력된 수와 동일한 경우가 없을 때, i는 for문을 다 돌고, i==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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        String s = br.readLine();
        int N = Integer.parseInt(s);
 
        int i = 0;
        for (i = N - s.length() * 9; i < N; i++) {
            int num = i;
            int sum = 0;
 
            while (num != 0) {
                sum += num % 10;
                num /= 10;
            }
 
            if ((sum + i) == N) {
                bw.write(i + "");
                break;
            }
        }
 
        if (i == N) {
            bw.write("0");
        }
        bw.flush();
        bw.close();
 
    }
 
}
 
 
 

⭐ 생성자의 범위

    - 생성자 + 자리수의 합 == 입력값

    - 생성자 == 입력값 - 자리수의 합

    - 자리수의 합이 최대일 경우, 생성자는 최소

    - 만일 생성자 후보가 자리수 합이 최대일 때의 생성자보다 작다면 입력값을 만들 수 없음

 

🤔 추가

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
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        String s = br.readLine();
        int N = Integer.parseInt(s);
 
        int i = 1;
        for (i = N - s.length() * 9>=1 ? N - s.length() * 9 : 0; i < N; i++) {
            int num = i;
            int sum = 0;
 
            while (num != 0) {
                sum += num % 10;
                num /= 10;
            }
 
            if ((sum + i) == N) {
                bw.write(i + "");
                break;
            }
        }
 
        if (i == N) {
            bw.write("0");
        }
        bw.flush();
        bw.close();
 
    }
 
}
 
 
 

- 생성자는 자연수이므로 i의 최소값을 1로 변경

 

 

 

🔗 소스 코드
HJ0216/TIL/BOJ

 

📚 참고 자료

 

[백준] 2231번 : 분해합 - JAVA [자바]

www.acmicpc.net/problem/2231 2231번: 분해합 문제 어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다

st-lab.tistory.com