문제
- 문제 링크
- 네개의 원형 바퀴 형태를 가진 자물쇠가 있다. 각 바퀴는
0~9의 값을 갖고, 바퀴를 돌려서 슬롯에 값을 맞출 수 있다. 자물쇠는 "0000"으로 세팅되어 있다. 그리고 문자열 배열인 deadends와 문자열 target이 주어진다. deadends에는 특정 자물쇠 값들이 들어있는데, 자물쇠가 deadends에 있는 값과 같아지면 자물쇠는 열 수 없게 된다. target은 자물쇠를 열 수 있는 값이다. deadends에 막히지 않고 target에 도달하기 위해 자물쇠 바퀴를 돌릴 때, 가장 짧은 횟수를 구해야 한다. 만약 도달할 수 없다면 -1을 반환한다.
- 제약 조건
- deadends 길이:
1 <= deadends.length <= 500
- target은 deadends에 포함되지 않는다.
풀이
풀기 전
target에 도달하기 위한 필승법이 있을까 했는데 딱히 없는 거 같았다. 자물쇠의 경우의 수를 계산했을 때 10^4로 그리 크지 않아서 모든 경우의 수를 체크할 수 있겠다 싶었다.
- 경우의 수가 작아서
DFS로 돌려도 되지만, 최단 거리를 구하는 문제이기 때문에 BFS를 사용하면 런타임 시간을 조금은 줄일 수 있을 거 같다.
코드
class Solution {
private int BFS(Set<String> dead, String target) {
Queue<StringBuilder> q = new LinkedList<>();
q.add(new StringBuilder("0000"));
int depth = 0;
while (!q.isEmpty()) {
int size = q.size();
for (int i=0; i<size; i++) {
StringBuilder now = q.poll();
for (int k=0; k<4; k++) {
StringBuilder[] next = new StringBuilder[2];
next[0] = new StringBuilder(now);
next[1] = new StringBuilder(now);
next[0].setCharAt(k, (char) ((now.charAt(k) - '0' + 1) % 10 + '0'));
next[1].setCharAt(k, (char) ((now.charAt(k) - '0' + 9) % 10 + '0'));
for (StringBuilder sb : next) {
if (dead.contains(sb.toString()))
continue;
if (target.equals(sb.toString()))
return depth + 1;
q.add(sb);
dead.add(sb.toString());
}
}
}
depth++;
}
return -1;
}
public int openLock(String[] deadends, String target) {
if (target.equals("0000"))
return 0;
Set<String> dead = new HashSet<>();
for (String s : deadends) {
dead.add(s);
}
if (dead.contains("0000"))
return -1;
return BFS(dead, target);
}
}
푼 후
- 풀이를 생각하는 건 어렵지 않았는데, 문자열 다루는 게 까다로웠다. 문자열을 정수형으로 바꿨다가
StringBuilder로 썼다가 그랬다. 정수형의 경우엔 문자열에서 왔다갔다 하는 게 오히려 느릴 거 같았고, 문자열을 그대로 사용하기에도 느려서 StringBuilder를 사용했다.
- 자물쇠 바퀴 하나에서 가능한 숫자 개수를
n이라고 하면 시간 복잡도는 O(n^4)이다. set에는 최대 자물쇠에서 가능한 수만큼 들어갈 수 있기 때문에 공간 복잡도도 O(n^4)이다.