https://www.acmicpc.net/problem/1543

 

1543번: 문서 검색

세준이는 영어로만 이루어진 어떤 문서를 검색하는 함수를 만들려고 한다. 이 함수는 어떤 단어가 총 몇 번 등장하는지 세려고 한다. 그러나, 세준이의 함수는 중복되어 세는 것은 빼고 세야 한

www.acmicpc.net

 

[난이도]

- Silver 5

 

[알고리즘]

- 부르트 포스

- 문자열

 

[정답 코드]

import java.io.*;
import java.util.*;

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

        String words = br.readLine();
        String searchWord = br.readLine();
        int answer = 0;

        while (words.contains(searchWord)) {
            words = words.replaceFirst(searchWord, "_");
            answer++;
        }
        System.out.println(answer);

    }
}

 

[풀이]

1. 문서속에 검색하고 싶은 단어가 포함되면 while문 반복

2. 문서속에 검색하고 싶은 단어를 임의로 "_"로 변경 (String.replaceFirst() 메서드를 활용)

3. 변경했다면 answer 1증가

4. answer 출력

'코딩테스트' 카테고리의 다른 글

백준 2057: 팩토리얼 분해[JAVA]  (0) 2024.04.10
백준 1476: 날짜 계산[JAVA]  (0) 2024.04.09
백준 1436: 영화감독 숌[JAVA]  (0) 2024.04.09
백준 1251: 단어 나누기[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04

https://www.acmicpc.net/problem/1436

 

1436번: 영화감독 숌

666은 종말을 나타내는 수라고 한다. 따라서, 많은 블록버스터 영화에서는 666이 들어간 제목을 많이 사용한다. 영화감독 숌은 세상의 종말 이라는 시리즈 영화의 감독이다. 조지 루카스는 스타워

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

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

        int N = Integer.parseInt(br.readLine());

        int count = 1;
        int number = 666;
        while (count != N) {
            number++;
            if (String.valueOf(number).contains("666")) {
                count++;
            }
        }
        System.out.println(number);
    }
}

 

[알고리즘]

- 부르트 포스

 

[풀이]

처음엔 생각보다 어려워보여서 실버 5 문제가 맞나? 라고 의심했었다. 알고보니 정말 부르트하게 풀었더니 정답이였다.

1. 666부터 1씩 증가시키며 숫자에 666이 포함됬을 경우 count를 1 증가시킨다.

2. count가 N이 됬을 경우 number를 출력한다

'코딩테스트' 카테고리의 다른 글

백준 1476: 날짜 계산[JAVA]  (0) 2024.04.09
백준 1543: 문서 검색[JAVA]  (0) 2024.04.09
백준 1251: 단어 나누기[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04
백준 2110번: 공유기 설치[JAVA]  (1) 2024.04.04

https://www.acmicpc.net/problem/1251

 

1251번: 단어 나누기

알파벳 소문자로 이루어진 단어를 가지고 아래와 같은 과정을 해 보려고 한다. 먼저 단어에서 임의의 두 부분을 골라서 단어를 쪼갠다. 즉, 주어진 단어를 세 개의 더 작은 단어로 나누는 것이다

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

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

        String input = br.readLine();

        String left = "";
        String mid = "";
        String right = "";

        ArrayList<String> list = new ArrayList<>();

        for (int i = 1; i < input.length() - 1; i++) {
            left = input.substring(0, i);
            for (int j = i + 1; j < input.length(); j++) {
                String tmp = new String();
                mid = input.substring(i, j);
                right = input.substring(j);
                tmp += backward(left);
                tmp += backward(mid);
                tmp += backward(right);
                list.add(tmp);
            }
        }
        Collections.sort(list);
        System.out.println(list.get(0));
    }
    static String backward(String word) {
        String tmp = "";
        for (int i = word.length() - 1; i >= 0; i--) {
            tmp += word.charAt(i);
        }
        return tmp;
    }
}

 

[알고리즘]

- 부르트포스 알고리즘

- 문자열

 

[풀이]

1. 이중 for문을 돌며 String.substring()을 활용해 left, mid, right의 3단어로 나눈다.

2. 문자열을 거꾸로 치환시키는 메서드 backward로 만들어 새 문자열을 만든다.

3. 새로 만든 문자열을 ArrayList에 추가한다.

4. Collections.sort() 메서드를 활용해 사전순으로 정렬한다.

5. list의 맨 앞 문자열을 출력한다.

 

이 방법이외에도 StringBuilder 를 활용하면 Stringbuilder에 자체적으로 문자열을 뒤집는 Stringbuilder.reverse()를 활용하면 더 간단하게 풀 수 있다.

'코딩테스트' 카테고리의 다른 글

백준 1543: 문서 검색[JAVA]  (0) 2024.04.09
백준 1436: 영화감독 숌[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04
백준 2110번: 공유기 설치[JAVA]  (1) 2024.04.04
백준 1987번: 알파벳[JAVA]  (1) 2024.04.03

https://www.acmicpc.net/problem/4179

 

4179번: 불!

입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다. 각각의 문자

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

public class Main {
    static int R, C, answer = Integer.MAX_VALUE;
    static char[][] graph;
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    static Queue<int[]> jihoon = new LinkedList<>(); // 지훈이의 좌표가 담긴 큐
    static Queue<int[]> fire = new LinkedList<>(); // 불의 좌표가 담긴 큐
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        graph = new char[R][C];
        for (int i = 0; i < R; i++) {
            String input = br.readLine();
            for (int j = 0; j < C; j++) {
                graph[i][j] = input.charAt(j);
                if (graph[i][j] == 'J') {
                    jihoon.offer(new int[]{i, j});
                }
                if (graph[i][j] == 'F') {
                    fire.offer(new int[]{i, j});
                }
            }
        }
        br.close();

        int answer = 0;
        while (true) {
            answer++; // while 반복문을 1회 시행할 때 마다 1분이 지난것이므로 1씩 증가
            int fireSize = fire.size(); // 불의 좌표가 담긴 큐의 크기 == 불의 갯수
            while (fireSize > 0) { // 번져야 할 불의 개수만큼만 반복, 이미 번진 불은 번지는것을 반복하지 않음
                fireSize--;
                int[] tmp = fire.poll();
                int x = tmp[0];
                int y = tmp[1];
                for (int i = 0; i < 4; i++) {
                    int nx = x + dx[i];
                    int ny = y + dy[i];
                    if (nx >= 0 && nx < R && ny >= 0 && ny < C) {
                        if (graph[nx][ny] == '.' || graph[nx][ny] == 'J') { // 불이 번진 위치가 벽이 아니라면
                            fire.offer(new int[]{nx, ny}); // 새로운 불의 좌표를 큐에 담는다
                            graph[nx][ny] = 'F'; // 번진만큼 지도를 갱신
                        }
                    }
                }
            }

            int jihoonSize = jihoon.size();
            while (jihoonSize > 0) { // 지훈이의 좌표가 담긴 큐가 비어있지 않을 경우
                jihoonSize--; // 새로운 지훈이의 좌표갯수만큼만 반복, 이미 이동한 지훈이는 이동하는것을 또 반복하지 않음
                int[] tmp = jihoon.poll();
                int x = tmp[0];
                int y = tmp[1];
                for (int i = 0; i < 4; i++) {
                    int nx = x + dx[i];
                    int ny = y + dy[i];
                    if (nx < 0 || nx >= R || ny < 0 || ny >= C) { // 탈출을 했을 경우
                        System.out.println(answer);
                        return;
                    }
                    if (graph[nx][ny] == '.') { // 이동가능한 자리일 경우
                        jihoon.offer(new int[]{nx, ny}); // 이동한 위치의 좌표를 큐에 담는다
                        graph[nx][ny] = 'J'; // 이동한 위치를 J로 갱신 (사실 이 코드는 필요하지는 않음)
                    }
                }
            }
            if (jihoon.isEmpty()) { // 새로이동할 때마다 지훈이의 좌표가 담긴 큐 jihoon 이 늘어나는데, 이동이 불가능하면 큐가 비게 됨
                System.out.println("IMPOSSIBLE");
                return;
            }
        }
    }
}

 

[설명]

bfs심화문제이다. 지훈이가 4방탐색을 하며 지도밖을 나갈 경우 반복문이 종료되는 것까지를 구현하는것은 약간만 생각하면 할 수 있다. 하지만 다른문제와 다른것은 지훈이가 4방탐색을함과 동시에 불도 4방으로 퍼져나간다는것을 생각해야 한다. 나는 이부분에서 막혀서 다른글을 참고했다. 

 

대략적인 풀이방식은 이렇다 : 

1. 불과 지훈이의 좌표를 각 큐에 담는다.

2. 불이 먼저 퍼져나가며 퍼져나간 불의 위치를 큐에 담는다.

3. 지훈이가 4방탐색을 하며 지훈이가 갈 수 있는 모든위치의 좌표를 큐에 담는다.

4. 이미 퍼져나간 불은 한 번더 퍼져나갈필요가없다. 새롭게 퍼져나간 불만 다시 퍼져나간다. (애초에 이미 퍼져나간불은 큐에 좌표가 없다.)

5. 3에서 4방탐색을 하며 지훈이가 갈 수 있는 모든 위치에서 다시 4방탐색을 하며 탈출구를 찾는다.

6. 4, 5를 반복한다.

7 - 1. 지훈이의 좌표가 지도 밖을 나갈경우 정답을 출력해준다.

7 - 2. 지훈이가 더이상 새롭게 이동할수 있는 위치가 없을 경우 jihoon 큐에는 더이상 값이 안담겨있기 때문에 IMPOSSIBLE을 출력해준다.

 

디버깅모드를 하고 지도의 모습을 시뮬레이션한것을 보면 약간은 신기하다. 여기서 중요한점은 불이 지훈이의 위치가 담긴 자리까지 불이 번져나가며 덮어버리는 경우가 있는데. 단순히 지도에서만 그렇고 지훈이의 좌표는 jihoon 큐 안에 담겨있기 때문에 문제없다.

 

'코딩테스트' 카테고리의 다른 글

백준 1436: 영화감독 숌[JAVA]  (0) 2024.04.09
백준 1251: 단어 나누기[JAVA]  (0) 2024.04.09
백준 2110번: 공유기 설치[JAVA]  (1) 2024.04.04
백준 1987번: 알파벳[JAVA]  (1) 2024.04.03
백준 1806번: 부분합[JAVA]  (0) 2024.04.02

https://www.acmicpc.net/problem/2110

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

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

        int N = Integer.parseInt(st.nextToken());
        int C = Integer.parseInt(st.nextToken());
        int[] arr = new int[N];

        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }
        Arrays.sort(arr);

        int result = 0;
        int left = 0;
        int right = arr[N - 1] - arr[0]; // 최대 간격

        while (left <= right) {
            int cnt = 1;
            int cur = arr[0]; // 첫 번째 집부터 시작

            int mid = (right + left) / 2; //공유기 설치의 최소 간격

            for (int i = 1; i < N; i++) { // 첫 번째집은설치했으니 두번째집부터 시작
                if (arr[i] - cur >= mid) {
                    cnt++;
                    cur = arr[i]; // 현재 바라보는 인덱스(커서)를 설치한 집으로 이동
                }
            }

            if (cnt >= C) { // 공유기간의 거리를 적당히 설정해서 최소 C개만큼 설치했을 경우
                result = mid;

                // 좀더 좋은 결과값을 찾기위해 간격을 넓혀본다
                left = mid + 1;
            } else {
                // 결과값을 찾기위해 간격을 좁힌다
                right = mid - 1;
            }
        }
        System.out.println(result);
    }
}

 

[설명]

공유기를 설치한 집과 다음 설치할 집과의 간격이 mid 이상일 경우에만 cnt를 1씩 증가시킨다. for문이 끝난 후 cnt 의 값이 C이상일 경우 좀더 최적의 해를 찾기위해 간격을 넓혀서 재탐색해본다. 우리는 최댓값을 찾는것이기 때문이다. cnt의 값이 C보다 적을 경우 간격을 좁혀 해를 재탐색한다.

'코딩테스트' 카테고리의 다른 글

백준 1251: 단어 나누기[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04
백준 1987번: 알파벳[JAVA]  (1) 2024.04.03
백준 1806번: 부분합[JAVA]  (0) 2024.04.02
백준 1253번: 좋다[JAVA]  (0) 2024.04.02

https://www.acmicpc.net/problem/1987

 

1987번: 알파벳

세로 $R$칸, 가로 $C$칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 ($1$행 $1$열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

public class Main {
    static int R, C, answer = 0;
    static char[][] graph;
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    static HashSet<Character> alphabet;
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        graph = new char[R][C];

        for (int i = 0; i < R; i++) {
            String input = br.readLine();
            for (int j = 0; j < C; j++) {
                graph[i][j] = input.charAt(j);
            }
        }
        alphabet = new HashSet<>(); // HashSet 초기화
        back(0, 0, 1); //
        System.out.println(answer);
    }
    static void back(int x, int y, int count) {
        answer = Math.max(answer, count);
        alphabet.add(graph[x][y]);
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx >= 0 && nx < R && ny >= 0 && ny < C) {
                if (!alphabet.contains(graph[nx][ny])) { // 처음 방문한 알파벳일 경우
                    back(nx, ny, count + 1);
                }
            }
        }
        alphabet.remove(graph[x][y]); // 이전 상태로 돌아가기 위해 제거
    }
}

 

[설명]

백트래킹 문제이다.

일반적인 백트래킹 알고리즘과 다른점은 단순 방문했던 자리를 체크하는게 아니라 똑같은 알파벳이 아닌자리를 체크해줘야한다. 그 부분은 HashSet을 이용해 체크해주었다. 그리고 alphabet.remove()를 활용해 지나온 알파벳을 지우며 이전상태로 돌아간다.

https://www.acmicpc.net/problem/1806

 

1806번: 부분합

첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다.

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

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

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

        int[] arr = new int[N+1];
        st = new StringTokenizer(br.readLine(), " ");
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }
        int answer = Integer.MAX_VALUE;
        int left = 0;
        int right = 0;
        int sum = 0;

        while (left <= N && right <= N) {
            if (sum >= S) {
                answer = Math.min(answer, right - left);
                sum -= arr[left++];
            } else if (sum < S) {
                sum += arr[right++];
            }
        }
        System.out.println(answer==Integer.MAX_VALUE ? 0 : answer);
    }
}

 

[설명]

투포인터 알고리즘을 활용한다.

sum 이 S보다 작을 경우 sum += arr[right++]를 하고

sum이 S보다 크거나 같을 경우 sum -= arr[left--]를 해준다. 그리고 동시에 right - left를 해주어 더 작은값을 출력해준다.

https://www.acmicpc.net/problem/1253

 

1253번: 좋다

첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수)

www.acmicpc.net

 

 

[정답 코드]

import org.w3c.dom.html.HTMLParagraphElement;

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        int N = Integer.parseInt(st.nextToken());

        int[] arr = new int[N];
        st = new StringTokenizer(br.readLine(), " ");
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }
        Arrays.sort(arr);
        int answer = 0;

        for (int i = 0; i < N; i++) {
            int left = 0;
            int right = N - 1;
            int target = arr[i];
            while (left < right) {
                int sum = arr[left] + arr[right];
                if (sum == target) { // sum이 target과 같을 경우
                    if (left != i && right != i) { // left와 right가 같은 수가 아닐경우
                        answer++;
                        break;
                    } else if (left == i) { // 현재 탐색하려는 숫자를 사용하면 안됨
                        left++;
                    } else { // 현재 탐색하려는 숫자를 사용하면 안됨
                        right--;
                    }
                } else if (sum < target) { //sum이 target보다 작을 경우
                    left++;
                } else { // sum이 target보다 클 경우
                    right--;
                }
            }
        }
        System.out.println(answer);
    }
}

 

[설명]

투 포인터로 풀었다. 배열을 입력받은 후 arr[left] 와 arr[right]를 더한값을 target 과 비교해가며 left를 늘리고 right를 줄이며 탐색한다.

                    if (left != i && right != i) { // left와 right가 같은 수가 아닐경우
                        answer++;
                        break;
                    } else if (left == i) { // 현재 탐색하려는 숫자를 사용하면 안됨
                        left++;
                    } else { // 현재 탐색하려는 숫자를 사용하면 안됨
                        right--;
                    }

 여기서 else if 구문과 else 구문이 이해가 너무안가서 1시간 넘게 이해를 못하고있었다. 

예를 들어 현재 3번 인덱스를 target으로 두고 탐색하고있을 때, 3번인덱스 + X인덱스를 더한값을 찾으려고 했을 경우라는 의미이다. 3번인덱스를 찾으려는데 3번인덱스를 더해서 찾는건 말이 안되기 때문이다.

+ Recent posts