[Algorithm] boj_10942 (DP)

bagt13·2025년 3월 21일
0

Algorithm

목록 보기
14/18
post-thumbnail

문제

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

명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.

먼저, 홍준이는 자연수 N개를 칠판에 적는다. 그 다음, 명우에게 질문을 총 M번 한다.

각 질문은 두 정수 S와 E(1 ≤ S ≤ E ≤ N)로 나타낼 수 있으며, S번째 수부터 E번째 까지 수가 팰린드롬을 이루는지를 물어보며, 명우는 각 질문에 대해 팰린드롬이다 또는 아니다를 말해야 한다.

예를 들어, 홍준이가 칠판에 적은 수가 1, 2, 1, 3, 1, 2, 1라고 하자.

  • S = 1, E = 3인 경우 1, 2, 1은 팰린드롬이다.
  • S = 2, E = 5인 경우 2, 1, 3, 1은 팰린드롬이 아니다.
  • S = 3, E = 3인 경우 1은 팰린드롬이다.
  • S = 5, E = 7인 경우 1, 2, 1은 팰린드롬이다.

자연수 N개와 질문 M개가 모두 주어졌을 때, 명우의 대답을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수열의 크기 N (1 ≤ N ≤ 2,000)이 주어진다.

둘째 줄에는 홍준이가 칠판에 적은 수 N개가 순서대로 주어진다. 칠판에 적은 수는 100,000보다 작거나 같은 자연수이다.

셋째 줄에는 홍준이가 한 질문의 개수 M (1 ≤ M ≤ 1,000,000)이 주어진다.

넷째 줄부터 M개의 줄에는 홍준이가 명우에게 한 질문 S와 E가 한 줄에 하나씩 주어진다.

출력

총 M개의 줄에 걸쳐 홍준이의 질문에 대한 명우의 답을 입력으로 주어진 순서에 따라서 출력한다. 팰린드롬인 경우에는 1, 아닌 경우에는 0을 출력한다.


접근 방법

  • 처음에는 DP를 활용하지 않고 입력이 주어질때마다 해당 부분이 팰린드롬인지 확인했는데, 시간 초과가 발생했다. 질문의 개수가 최대 100만개이기 때문에, 입력때마다 탐색해야하기 때문이다.
  • 2차원 배열 boolean dp[i][k] 를 먼저 채운 후에, 입력때마다 해당 dp 값을 체크한다.
  • dp[i][k]는 인덱스 i부터 k까지가 팰린드롬인지를 담고있다.
  1. i == k 일 경우에는 항상 팰린드롬이다.
  2. k - i == 1 일 경우에는, numbers[i] == numbers[k] 일때만 팰린드롬이다.
  3. k - i ≥ 2 일 경우에는, numbers[i] == numbers[k] && dp[i + 1][k - 1] 일때 팰린드롬이다.
    • 여기서는, k - i == 2 일때부터 순차적으로 채워나가기 때문에, dp[i + 1][k - 1] 의 값은 항상 채워져있다.

시간 초과

public class boj_10942 {

    static int N, M;
    static int[] numbers;
    static StringBuilder sb;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());
        numbers = new int[N + 1];

        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 1; i < N + 1; i++) {
            numbers[i] = Integer.parseInt(st.nextToken());
        }

        sb = new StringBuilder();

        M = Integer.parseInt(br.readLine());
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            int startIdx = Integer.parseInt(st.nextToken());
            int endIdx = Integer.parseInt(st.nextToken());

            checkPalindrome(startIdx, endIdx);

        }

        System.out.println(sb);
    }
			//endIdx - startIdx % 2 == 0 일 경우
            //start ~ start+(end-start)/2+1 만큼 조회 후 1개 pop

            //endIdx - startIdx % 2 != 0 일 경우
            //start ~ start + (end-start)/2+1 만큼 조회
            
    static void checkPalindrome(int startIdx, int endIdx) {
        boolean isPalindrome = true;
        Stack<Integer> stack = new Stack<>();

        int searchCnt = startIdx + (endIdx - startIdx) / 2 + 1;

        for (int i = startIdx; i < searchCnt; i++) {
            stack.push(numbers[i]);
        }

        if ((endIdx - startIdx) % 2 == 0) stack.pop();

        for (int i = searchCnt; i <= endIdx; i++) {
            Integer pop = stack.pop();
            if (pop != numbers[i]) {
                isPalindrome = false;
                break;
            }
        }

        sb.append(isPalindrome ? 1 : 0).append("\n");
    }
}

DP 성공

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

public class boj_10942 {

    static int N, M;
    static int[] numbers;
    static boolean[][] dp;
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());
        numbers = new int[N + 1];
        dp = new boolean[N + 1][N + 1];

        //input
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 1; i < N + 1; i++) {
            numbers[i] = Integer.parseInt(st.nextToken());
        }

        //set
        setDP(numbers, numbers.length);

        M = Integer.parseInt(br.readLine());
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            int startIdx = Integer.parseInt(st.nextToken());
            int endIdx = Integer.parseInt(st.nextToken());

            sb.append(dp[startIdx][endIdx] ? 1 : 0).append("\n");
        }

        System.out.println(sb);
    }

    static void setDP(int[] numbers, int length) {
        for (int i = 1; i < length; i++) {
            dp[i][i] = true;
        }

        for (int i = 1; i < length - 1; i++) {
            if (numbers[i] == numbers[i + 1]) {
                dp[i][i + 1] = true;
            }
        }

        for (int i = 2; i < length; i++) {
            for (int k = 1; k < length - i; k++) {
                if (numbers[k] == numbers[k + i] && dp[k + 1][k + i - 1]) {
                    dp[k][k + i] = true;
                }
            }
        }
    }
}
profile
백엔드 개발자입니다😄

0개의 댓글