[프로그래머스] 풍선 터트리기 - Java

JeongYong·2023년 5월 31일
0

Algorithm

목록 보기
156/263

문제 링크

https://school.programmers.co.kr/learn/courses/30/lessons/68646

문제 설명

일렬로 나열된 n개의 풍선이 있습니다. 모든 풍선에는 서로 다른 숫자가 써져 있습니다. 당신은 다음 과정을 반복하면서 풍선들을 단 1개만 남을 때까지 계속 터트리려고 합니다.

  1. 임의의 인접한 두 풍선을 고른 뒤, 두 풍선 중 하나를 터트립니다.
  2. 터진 풍선으로 인해 풍선들 사이에 빈 공간이 생겼다면, 빈 공간이 없도록 풍선들을 중앙으로 밀착시킵니다.

여기서 조건이 있습니다. 인접한 두 풍선 중에서 번호가 더 작은 풍선을 터트리는 행위는 최대 1번만 할 수 있습니다. 즉, 어떤 시점에서 인접한 두 풍선 중 번호가 더 작은 풍선을 터트렸다면, 그 이후에는 인접한 두 풍선을 고른 뒤 번호가 더 큰 풍선만을 터트릴 수 있습니다.

당신은 어떤 풍선이 최후까지 남을 수 있는지 알아보고 싶습니다. 위에 서술된 조건대로 풍선을 터트리다 보면, 어떤 풍선은 최후까지 남을 수도 있지만, 어떤 풍선은 무슨 수를 쓰더라도 마지막까지 남기는 것이 불가능할 수도 있습니다.

일렬로 나열된 풍선들의 번호가 담긴 배열 a가 주어집니다. 위에 서술된 규칙대로 풍선들을 1개만 남을 때까지 터트렸을 때 최후까지 남기는 것이 가능한 풍선들의 개수를 return 하도록 solution 함수를 완성해주세요.

제한 사항

  • a의 길이는 1 이상 1,000,000 이하입니다.
  • a[i]는 i+1 번째 풍선에 써진 숫자를 의미합니다.
  • a의 모든 수는 -1,000,000,000 이상 1,000,000,000 이하인 정수입니다.
  • a의 모든 수는 서로 다릅니다.

알고리즘: 구현

풀이

내가 푼 방식은 다른 풀이 보다 비효율적일 수도 있지만, 꽤 직관적으로 이해하기 쉽게 풀었다.

내가 푼 아이디어는 이렇다.
더 큰 값을 터트리는 연산은 무한으로 가능하기 때문에 가장 작은 값은 무조건 남을 수 있다. 이 점을 이용했다.
가장 작은 값을 지우면 그다음으로 작은 값이 남게 된다. -> (번호가 더 작은 풍선을 터트리는 연산 1회)

먼저, answer은 1로 시작한다. -> 제일 작은 값은 무조건 남기 때문에
그리고 가장 작은 값을 기준으로 왼쪽 큐, 오른쪽 큐로 나눴다.
그리고 가장 작은 값 다음으로 작은 값이 위치한 큐를 찾는다. 그 값이 터지지 않았다면
answer += 1 해 주고 해당 큐에서 그 값이 나올 때까지 poll() 해준다. 왜냐하면 인접한 풍선을 고르고 연산하기 때문에 필연적으로 터트려 줘야 하는 풍선들이다. 터트린 풍선들은 visited 처리를 해준다.
위 방식을 왼쪽 큐와 오른쪽 큐에 요소가 없을 때까지 반복한다.

소스 코드

import java.util.*;
class Node {
    int index, value;
    Node(int index, int value) {
        this.index = index;
        this.value = value;
    }
}
class Solution {
    static ArrayList<Node> sorted_a = new ArrayList<>();
    static HashMap<Integer, Boolean> visited = new HashMap<>();
    public int solution(int[] a) {
        if(a.length == 1) return 1;
        int answer = 1;
        int min = Integer.MAX_VALUE;
        int min_index = -1;
        for(int i=0; i<a.length; i++) {
            sorted_a.add(new Node(i, a[i]));
            if(min > a[i]) {
                min = a[i];
                min_index = i;
            }
        }
        Collections.sort(sorted_a, (o1, o2) -> {return o1.value - o2.value;});
        Queue<Integer> left_que = new LinkedList<>();
        for(int i=min_index - 1; i>=0; i--) left_que.add(a[i]);
        Queue<Integer> right_que = new LinkedList<>();
        for(int i=min_index + 1; i<a.length; i++) right_que.add(a[i]);
        int search_index = 1;
        while(left_que.size() != 0 || right_que.size() != 0) {
            int ind = sorted_a.get(search_index).index;
            int val = sorted_a.get(search_index).value;
            if(ind < min_index) {
                //왼쪽 큐에 존재한다.
                if(visited.get(val) == null) {
                    //아직 해당값이 나온적이 없음.
                    answer += 1;
                    pop_balloon(val, left_que);
                }
            } else if(ind > min_index) {
                //오른쪽 큐에 존재한다.
                if(visited.get(val) == null) {
                    answer += 1;
                    pop_balloon(val, right_que);
                }
            }
            search_index += 1;
        }
        return answer;
    }
    static void pop_balloon(int value, Queue<Integer> que) {
        while(true) {
            int n = que.poll();
            visited.put(n, true); //방문처리
            if(n == value) return;
        }
    }
}

0개의 댓글