문제 링크
https://programmers.co.kr/learn/courses/30/lessons/70130
풀이
전체적인 풀이 과정은 다음과 같다.
- 주어진 배열 속 숫자들의 개수를 카운트 (HashMap 사용), 이를 우선순위 큐를 통해 내림차순으로 정렬 (숫자, 숫자 개수)
- 우선순위 큐에서 개수가 많은 숫자대로 꺼내 배열을 순서대로 탐색하면 해당 숫자가 걸린 위치에서 탐색
- 위치가 처음이라면 뒤에 숫자가 동일하지 않다면 수열에 포함
- 위치가 마지막이라면 그 앞의 숫자가 동일하지 않고 수열에 포함이 안되어 있다면 수열에 포함
- 위치가 중간이라면 앞 뒤 숫자들에 대해 조건 탐색 후 수열에 포함 (앞 숫자를 먼저 탐색)
- 위의 조건대로 수열에 쌍이 추가될수록 +2를 추가하고, 최종 수열 길이와 답을 비교해 더 큰 값을 저장
- 우선순위 큐에서 숫자를 꺼내 탐색을 반복하다 숫자 개수*2 가 답보다 작다면 탐색 종료
이 문제 속 스타 수열의 경우 조건이 매우 복잡해, 단순한 완전 탐색으로 일일히 조건에 맞는 수열을 찾기에는 매우 복잡해진다. 그래서 문제의 조건 속 하나는 무조건 만족하게 한 상태로 탐색을 시작해야 문제 해결이 쉬워지는데, 이 경우 수열 속 각 쌍에 동일한 숫자가 존재해야 함을 우선 해결하는 것이 좋다.
우선 주어진 a 배열을 돌며 숫자들의 개수를 센다(필자는 HashMap 사용). 이후 해당 숫자와 숫자의 개수를 하나의 클래스로 만든 다음 우선순위 큐에 모두 넣어, 숫자 개수의 내림차순으로 정렬되도록 전 처리를 진행한다. 이후엔 우선 순위 큐에서 숫자와 숫자 개수를 뽑아 탐색을 진행한다. 이 탐색의 목적은 a 배열을 순차대로 돌며 뽑은 숫자가 나왔을 때, 해당 숫자의 앞과 뒤 중 스타 수열의 쌍이 될 수 있는 지를 비교한 다음 가능하다면 수열에 추가해주는 것이다. 만약 해당 숫자 위치가 a 배열 시작이라면 무조건 뒤의 숫자를 추가하고, 숫자 위치가 배열 끝이라면 그 앞의 숫자와 함께 수열의 쌍이 될 수 있는 지, 중간이라면 숫자의 앞과 뒤가 수열의 쌍이 될 수 있는 지를 체크하고 포함된다면 수열의 길이 +2, 아니라면 다음 탐색을 반복하면 된다.
이렇게 하나의 수에 대해 스타 수열 길이를 계산하고 답과 비교해 더 큰 값을 저장하면 되며, 만약 다음 탐색에서 숫자의 개수가 n개인데 답이 2*n보다 크다면, 이는 해당 숫자의 탐색을 진행해봤자 구할 수 있는 스타 수열 최대 길이가 답보다 작기 때문에 탐색을 중지해버리면 된다.
class Solution {
public int solution(int[] a) {
int answer = 2;
HashMap<Integer, Integer> hashMap = new HashMap<>();
PriorityQueue<Infor> pq = new PriorityQueue<>();
if (a.length < 2) {
return 0;
} else if (a.length == 2) {
return 2;
}
for (int i = 0; i < a.length; i++) {//숫자들의 개수 카운트
if (hashMap.containsKey(a[i])) {
hashMap.replace(a[i], hashMap.get(a[i]) + 1);
} else {
hashMap.put(a[i], 1);
}
}
for (Map.Entry<Integer, Integer> elem : hashMap.entrySet()) {//우선순위 큐를 통해 내림차순
pq.add(new Infor(elem.getKey(), elem.getValue()));
}
while (!pq.isEmpty()) {//개수가 많은 숫자 순서대로
int result = 0, lastIndex = -1;
Infor infor = pq.poll();
if (answer >= infor.count * 2) {//최대 길이가 답을 못 넘는 경우
break;
}
for (int i = 0; i < a.length; i++) {
if (a[i] == infor.num) {//해당 숫자인 상태
if (i == 0) {//수열의 처음인 경우
if (a[i] != a[i + 1]) {
lastIndex = 1;
result += 2;
}
} else if (i == a.length - 1) {//수열의 마지막인 경우
if (lastIndex < i - 1 && a[i] != a[i - 1]) {//앞이 부분 수열에 포함 x
lastIndex = i;
result += 2;
}
} else {//수열의 중간인 경우
if (lastIndex < i - 1) {
if (a[i] != a[i - 1]) {//i 이전 인덱스 숫자를 부분 수열에 포함할 수 있는 경우
lastIndex = i;
result += 2;
} else if (a[i] != a[i + 1]) {//i 다음 인덱스 숫자를 부분 수열에 포함할 수 있는 경우
lastIndex = i + 1;
result += 2;
}
} else if (lastIndex == i - 1 && a[i] != a[i + 1]) {//i 다음 인덱스 숫자를 부분 수열에 포함할 수 있는 경우
lastIndex = i + 1;
result += 2;
}
}
}
}
answer = Math.max(answer, result); //최대값을 답으로 최신화
}
return answer;
}
class Infor implements Comparable<Infor>{//우선순위 큐 삽입용 클래스
int num, count;
public Infor(int num, int count) {
this.num = num;
this.count = count;
}
@Override
public int compareTo(Infor o) {
if (this.count > o.count) {
return -1;
} else {
return 1;
}
}
}
}
결과
'Algorithm > 코드 풀이' 카테고리의 다른 글
프로그래머스: 숫자 게임 [JAVA] (0) | 2022.03.26 |
---|---|
프로그래머스: 스티커 모으기 2 [JAVA] (0) | 2022.03.26 |
프로그래머스: 기지국 설치 [JAVA] (0) | 2022.03.22 |
프로그래머스: 공 이동 시뮬레이션 [JAVA] (0) | 2022.03.15 |
프로그래머스: 가장 긴 팰린드롬 [JAVA] (0) | 2022.03.15 |