수빈이는 A와 B로만 이루어진 영어 단어가 존재한다는 사실에 놀랐다.
대표적인 예로
이런 사실에 놀란 수빈이는 간단한 게임을 만들기로 했다.
두 문자열 와 가 주어졌을 때, 를 로 바꾸는 게임이다.
문자열을 바꿀 때는 다음과 같은 두 가지 연산만 가능하다.
주어진 조건을 이용해서 를 로 만들 수 있는지 없는지 알아내는 프로그램을 작성하시오.
첫째 줄에 가 둘째 줄에 가 주어진다.
를 로 바꿀 수 있으면 을 없으면 을 출력한다.
처음 단순하게 생각했을 때는 브루트 포스로 부터 시작해서 길이가 가 될 때까지
모든 경우의 수를 탐색하는 것이 가장 단순하다고 생각했습니다.
하지만 의 최대 길이 를 생각했을 때
시간 복잡도는 가 된다고 생각했기 때문에
말도 안되는 방법이라고 생각했습니다.
그렇다면 모든 경우를 탐색하는 것이 아니라
역추적 방법과 유사하게 문자열 를 지워나간다면 문제를 해결할 수 있을 것 같았습니다.
그리고 문제에서 주어진 두 가지 연산은
항상 맨 뒤쪽에 문자열을 추가하는 방식이기 때문에 가능하다고 생각했습니다.
그래서 문자열이 정방향인지 역방향인지 판별하는 isReverse라는 boolean 변수를 선언해
정방향일 때는 end 인덱스를 감소시키고
역방향일 때는 start 인덱스를 증가시키는 방법을 사용했고
이 문자열의 길이가 과 동일해질 때 문자열이 같은지 판별하는 재귀 메서드를 구현해 문제를 해결했습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static String S;
static int L;
static char[] word;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
S = br.readLine();
L = S.length();
word = br.readLine().toCharArray();
System.out.println(greedy(0, word.length - 1, false));
}
private static String greedy(int start, int end, boolean isReverse) {
if (Math.abs(end - start) + 1 == L) {
StringBuilder tmp = new StringBuilder();
String result;
if (isReverse) tmp.append(new String(word, end, L)).reverse();
else tmp.append(new String(word, start, L));
result = tmp.toString();
return S.equals(result) ? "1" : "0";
}
if (word[end] == 'A') {
if (isReverse) return greedy(start, end + 1, true);
else return greedy(start, end - 1, false);
}
else {
if (isReverse) return greedy(end + 1, start, !isReverse);
else return greedy(end - 1, start, !isReverse);
}
}
}
우선 로직은 깔끔히 구현됐지만 두 가지 부분이 아쉬웠습니다.
이 두 가지 생각을 기반으로 코드를 개선했습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static String S;
static int L;
static char[] word;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
S = br.readLine();
L = S.length();
word = br.readLine().toCharArray();
System.out.println(greedy());
}
private static String greedy() {
int N = word.length - L;
int start = 0;
int end = word.length - 1;
boolean isReverse = false;
while (N --> 0) {
char lastChar;
if (isReverse) {
lastChar = word[start];
} else {
lastChar = word[end];
}
if (lastChar == 'A') {
if (isReverse) {
start++;
} else {
end--;
}
} else {
if (isReverse) {
start++;
} else {
end--;
}
isReverse = !isReverse;
}
}
StringBuilder tmp = new StringBuilder();
String result;
if (isReverse) {
tmp.append(new String(word, start, L)).reverse();
} else {
tmp.append(new String(word, start, L));
}
result = tmp.toString();
return S.equals(result) ? "1" : "0";
}
}
재귀 방식 코드

개선된 while 방식 코드

코드는 단순화됐고 효율 또한 시간적으로나 공간적으로나 개선된 모습을 볼 수 있습니다.