131130 - 혼자 놀기의 달인
info
- 문제 보기: 131130 - 혼자 놀기의 달인
- 소요 시간: 22분 33초
- 풀이 언어:
java
- 체감 난이도: 2️⃣
- 리뷰 횟수: ✅
풀이 키워드
스포주의
구현
그래프
dfs
풀이 코드
info
- 메모리: 89600 KB
- 시간: 1 ms
import java.util.*;
class Solution {
int[] cards;
boolean[] visited;
int findCycle(int i) {
if (visited[i]) return 0;
visited[i] = true;
return findCycle(cards[i]-1) + 1;
}
public int solution(int[] cards) {
this.cards = cards;
visited = new boolean[cards.length];
List<Integer> clenList = new ArrayList<>();
// 1. 모든 사이클 뭉치를 찾는다 (길이만 구해두기)
for (int i = 0; i < cards.length; ++i) {
clenList.add(findCycle(i));
}
if (clenList.size() < 2) return 0;
// 2. 뭉치 길이 제일 긴거 2개 곱하기
Collections.sort(clenList, Collections.reverseOrder());
return clenList.get(0) * clenList.get(1);
}
}
풀이 해설
알고리즘 자체의 난이도보단 약간의 독해력과 방향 그래프 문제로 치환하는 능지가 요구된다.
그래프 구현까진 안가고 visited
처리로 사이클 뭉치만 잘 찾아주면 된다.
🔁 사이클 찾기 문제로 치환하기
지문에서 화려하게 설명했지만 결국 상자를 열면 다음에 열 상자 번호가 들어있다는 점에서, 사이클 찾으라는 소리다.
예를 들어 규칙대로 상자를 계속 열어봤더니 이런 순서로 열게 되었다고 가정해보자.
(마지막 3을 열었을 때 5가 들어있었고, 이미 5는 열려있으므로 끝)
상자를 열어본 순서
5 -> 1 -> 2 -> 4 -> 3
여기서 한 사이클 그룹이면 시작을 5로 하든 2로 하든 3으로 하든 결국 구성원은 똑같다는 점을 알 수 있다.
그리고 cards
의 값들이 서로 unique하기 때문에,
자기 자신을 가리키는 self-loop 노드를 포함해서, 모든 노드의 in-degree / out-degree는 1이다.
따라서 사이클끼리는 서로 겹치는 노드가 없다.
그래서 visited
를 통해 이미 열린 상자만 표시하면서 으로 모든 사이클을 찾아주면 된다.
심지어 사이클 멤버를 알 필요도 없다. 그냥 사이클 당 길이만 구해두면 된다.
호출부
for (int i = 0; i < cards.length; ++i) {
clenList.add(findCycle(i));
}
피호출부
int findCycle(int i) {
if (visited[i]) return 0;
visited[i] = true;
return findCycle(cards[i]-1) + 1;
}
그리고 이렇게 찾은 길이 값 중 가장 큰 2개의 값을 서로 곱해 정답을 구한다.
길이 값이 1개밖에 안나온다면 0점 처리한다.
if (clenList.size() < 2) return 0;
// 2. 뭉치 길이 제일 긴거 2개 곱하기
Collections.sort(clenList, Collections.reverseOrder());
return clenList.get(0) * clenList.get(1);
메모
- sorting boxed integer list in reverse order... 귀하군요
- 실버 3쯤으로 예상되는 다소 쉬운 문제