명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.
먼저, 홍준이는 자연수 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을 출력한다.
예제 입력 1
7
1 2 1 3 1 2 1
4
1 3
2 5
3 3
5 7
예제 출력 1
1
0
1
1
앞에서부터 읽으나 뒤에서부터 읽으나 똑같은 문자열을 팰린드롬(palindrome)이라고 한다.**
8글자로 이루어진 문자열이 팰린드롬이려면, 2번째~7번째 글자로 이루어진 문자열이 팰린드롬임과 동시에 첫번째 글자와 8번째 글자가 같아야 한다.
2번째~7번째 글자가 팰린드롬이려면 3번째~6번째 글자가 팰린드롬임과 동시에 2번째 글자와 7번째 글자가 같아야 하고.
이런 식으로 전체 문자열의 팰린드롬 여부가 하위 부분 문제로 결정되기 때문에 다이나믹 프로그래밍으로 접근할 수 있다.
import java.io.*;
import java.util.*;
class Main {
static int[] nums;
static int[][] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
nums = new int[N + 1];
dp = new int[N + 1][N + 1];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 1; i <= N; i++) {
nums[i] = Integer.parseInt(st.nextToken());
}
int M = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int S = Integer.parseInt(st.nextToken());
int E = Integer.parseInt(st.nextToken());
if (isPalindrome(S, E)) {
sb.append(1).append("\n");
} else {
sb.append(0).append("\n");
}
}
System.out.print(sb.toString());
}
private static boolean isPalindrome(int left, int right) {
if (left >= right) {
return true;
}
if (dp[left][right] == 1) {
return true;
} else if (dp[left][right] == -1){
return false;
}
if (nums[left] == nums[right] && isPalindrome(left + 1, right - 1)) {
dp[left][right] = 1;
return true;
}
dp[left][right] = -1;
return false;
}
}
dp[i][j] 배열에 i번째 수부터 j번째 수까지가 팰린드롬인지 여부를 메모이제이션했다. 값이 1이면 팰린드롬이 맞다는 뜻, -1이면 팰린드롬이 아니라는 뜻.
left >= right이면 확인해야 할 문자가 더 이상 남아 있지 않으므로 true를 리턴해주었다.
dp[i][j] 배열의 값이 0이 아니면 이미 팰린드롬 여부가 메모이제이션이 되어 있다는 뜻이니 바로 그 값에 따라 true/false를 리턴해주었다.
dp[i][j] 배열의 값이 0이면
left+1번째 수부터 right-1번째 수까지가 팰린드롬인지 확인하기 위해 재귀 호출을 해주었다.위 1번과 2번을 모두 만족시키는 경우에만 팰린드롬으로 판정했다.
