문제
명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.
먼저, 홍준이는 자연수 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개가 모두 주어졌을 때, 명우의 대답을 구하는 프로그램을 작성하시오.
풀이
우선 일반 팰린드롬 풀이로 풀었다.
M 이 1000000 까지 되기 때문에 시간초과가 날 것으로 보았으나, 예상 외로 가능했다.
<팰린드롬 풀이 코드>
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N, M;
static int[] A;
static StringBuilder sb = new StringBuilder();
public static int parseInt(String string) {
return Integer.parseInt(string);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = parseInt(br.readLine());
A = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i = 0 ; i < N ; i++) {
A[i] = parseInt(st.nextToken());
}
M = parseInt(br.readLine());
for(int i = 0 ; i < M ; i++) {
st = new StringTokenizer(br.readLine());
int start = parseInt(st.nextToken()) - 1;
int end = parseInt(st.nextToken()) - 1;
sb.append(getAnswer(start, end) + "\n");
}
System.out.println(sb);
}
static int getAnswer(int start, int end) {
while(start < end) {
if(A[start] != A[end]) {
return 0;
}
start++;
end--;
}
return 1;
}
}
하지만, 1000000개의 모든 것을 풀어내기 위해선 DP를 이용해야 할것으로 보고 풀이를 하였다.
방법은 dp[start][end] 의 수가 팰린드롬인지를 계속해서 저장하면 N^2 의 시간이 걸리므로 1000000보다 큰 경우를 하더라도 가능할 것으로 본다.
dp[i][i] 는 항상 팰린드롬이다
이때, dp[i][i + 1] 은 길이가 2인 팰린드롬을 미리 체크한다.
for(int i = 0 ; i < N ; i++) {
dp[i][i] = 1;
// 길이 2 인 팰린드롬
if(i != N - 1 && A[i] == A[i + 1]) {
dp[i][i + 1] = 1;
}
}
또, 길이가 3 ~ N 까지의 팰린드롬을 찾아준다.
이때 처음 과 끝이 같으면서 start + 1 ~ end - 1 의 범위의 수가 팰린드롬이라면 팰린드롬이 된다.
for(int i = 2; i < N; i++) {
for(int j = 0 ; j < N - i ; j++) {
if(A[j] == A[j + i] && dp[j + 1][j + i - 1] == 1) {
dp[j][j + i] = 1;
}
}
}
위와 같은 두개의 방법으로 dp 배열을 모두 정리한뒤 start end 에 따른 값을 확인해주면 된다.
<전체코드>
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N, M;
static int[] A;
static int[][] dp;
static StringBuilder sb = new StringBuilder();
public static int parseInt(String string) {
return Integer.parseInt(string);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = parseInt(br.readLine());
A = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i = 0 ; i < N ; i++) {
A[i] = parseInt(st.nextToken());
}
setDp();
M = parseInt(br.readLine());
for(int i = 0 ; i < M ; i++) {
st = new StringTokenizer(br.readLine());
int start = parseInt(st.nextToken()) - 1;
int end = parseInt(st.nextToken()) - 1;
sb.append(dp[start][end] + "\n");
}
System.out.println(sb);
}
static void setDp() {
dp = new int[N][N];
for(int i = 0 ; i < N ; i++) {
dp[i][i] = 1;
// 길이 2 인 팰린드롬
if(i != N - 1 && A[i] == A[i + 1]) {
dp[i][i + 1] = 1;
}
}
for(int i = 2; i < N; i++) {
for(int j = 0 ; j < N - i ; j++) {
if(A[j] == A[j + i] && dp[j + 1][j + i - 1] == 1) {
dp[j][j + i] = 1;
}
}
}
}
}
'알고리즘 공부 > DP' 카테고리의 다른 글
[리트코드] 238. Product of Array Except Self <Java> (0) | 2021.12.02 |
---|---|
[백준] 11066 파일 합치기 (0) | 2021.11.04 |
[백준] 12865 평범한 배낭 (0) | 2021.10.29 |
[백준] 2688 줄어들지 않아 (0) | 2021.08.07 |
[백준] 11062 카드 게임 (0) | 2021.08.07 |