문제 설명

방금그곡

라디오를 자주 듣는 네오는 라디오에서 방금 나왔던 음악이 무슨 음악인지 궁금해질 때가 많다. 그럴 때 네오는 다음 포털의 '방금그곡' 서비스를 이용하곤 한다. 방금그곡에서는 TV, 라디오 등에서 나온 음악에 관해 제목 등의 정보를 제공하는 서비스이다.

네오는 자신이 기억한 멜로디를 가지고 방금그곡을 이용해 음악을 찾는다. 그런데 라디오 방송에서는 한 음악을 반복해서 재생할 때도 있어서 네오가 기억하고 있는 멜로디는 음악 끝부분과 처음 부분이 이어서 재생된 멜로디일 수도 있다. 반대로, 한 음악을 중간에 끊을 경우 원본 음악에는 네오가 기억한 멜로디가 들어있다 해도 그 곡이 네오가 들은 곡이 아닐 수도 있다. 그렇기 때문에 네오는 기억한 멜로디를 재생 시간과 제공된 악보를 직접 보면서 비교하려고 한다. 다음과 같은 가정을 할 때 네오가 찾으려는 음악의 제목을 구하여라.

  • 방금그곡 서비스에서는 음악 제목, 재생이 시작되고 끝난 시각, 악보를 제공한다.
  • 네오가 기억한 멜로디와 악보에 사용되는 음은 C, C#, D, D#, E, F, F#, G, G#, A, A#, B 12개이다.
  • 각 음은 1분에 1개씩 재생된다. 음악은 반드시 처음부터 재생되며 음악 길이보다 재생된 시간이 길 때는 음악이 끊김 없이 처음부터 반복해서 재생된다. 음악 길이보다 재생된 시간이 짧을 때는 처음부터 재생 시간만큼만 재생된다.
  • 음악이 00:00를 넘겨서까지 재생되는 일은 없다.
  • 조건이 일치하는 음악이 여러 개일 때에는 라디오에서 재생된 시간이 제일 긴 음악 제목을 반환한다. 재생된 시간도 같을 경우 먼저 입력된 음악 제목을 반환한다.
  • 조건이 일치하는 음악이 없을 때에는 “(None)”을 반환한다.

입력 형식

입력으로 네오가 기억한 멜로디를 담은 문자열 m과 방송된 곡의 정보를 담고 있는 배열 musicinfos가 주어진다.

  • m은 음 1개 이상 1439개 이하로 구성되어 있다.
  • musicinfos는 100개 이하의 곡 정보를 담고 있는 배열로, 각각의 곡 정보는 음악이 시작한 시각, 끝난 시각, 음악 제목, 악보 정보가 ','로 구분된 문자열이다.
  • 음악의 시작 시각과 끝난 시각은 24시간 HH:MM 형식이다.
  • 음악 제목은 ',' 이외의 출력 가능한 문자로 표현된 길이 1 이상 64 이하의 문자열이다.
  • 악보 정보는 음 1개 이상 1439개 이하로 구성되어 있다.

출력 형식

조건과 일치하는 음악 제목을 출력한다.

 

입출력 예시

 

문제 풀이


1. 문제를 잘게잘게 쪼개서 어떤 것 부터 풀어야할 지 생각했다.

2. 먼저 주어진 musicinfos에 있는 String 배열을 쪼개야겠다는 생각을 했다.

3. 12:00-12:14 분 차이를 구하고, 그 분동안 곡들이 반복하는 것을 구상했다.

4. 배열 속에 n분 만큼 곡들을 반복하고 입력값이 같은 지 확인하면 된다.

5. contains함수를 사용한다.

첫 풀이 => 실패

import java.io.*;
import java.util.*;

class Solution {
    
    public int remainTime(String start, String end)
    {
        String[] s = start.split(":");
        String[] e = end.split(":");
        int startMin = Integer.parseInt(s[0] * 60) + Integer.parseInt(s[1]);
        int endMin = Integer.parseInt(e[0] * 60) + Integer.parseInt(e[1]);
        
        return endMin - startMin;   
    }
    
    
    
    public String solution(String m, String[] musicinfos) {
        String answer = "(None)";
        for (String info : musicinfos)
        {
            String[] parts = info.split(",");
            int times = 0;
            String title;
            String lyrics;
            times = remainTime(parts[0], parts[1]);
            title = parts[2];
            lyrics = parts[3];
            StringBuilder sb = new StringBuilder();
             for (int i=0; i<times; i++)
                sb.append(lyrics.charAt(i % lyrics.length()));
            String fullLyrics = sb.toString();
            if (fullLyrics.contains(m))
                answer = title;
        }
                
        
        
        return answer;
    }
}

 

C#, D#을 생각안하고 contains비교했더니 실패가 떴다.

정답풀이

import java.io.*;
import java.util.*;

class Solution {
    
    public int remainTime(String start, String end)
    {
        String[] s = start.split(":");
        String[] e = end.split(":");
        int startMin = Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]);
        int endMin = Integer.parseInt(e[0]) * 60 + Integer.parseInt(e[1]);
        
        return endMin - startMin;   
    }
    
    private String convertMelody(String s)
    {
        return s.replaceAll("C#", "c")
            .replaceAll("D#", "d")
            .replaceAll("F#", "f")
            .replaceAll("G#", "g")
            .replaceAll("A#", "a")
            .replaceAll("B#", "b");
    }
    
    
    public String solution(String m, String[] musicinfos) {
        String answer = "(None)";
        m = convertMelody(m);
        int maxTime = -1;
        for (String info : musicinfos)
        {
            String[] parts = info.split(",");
            int times = remainTime(parts[0], parts[1]);
            String title = parts[2];
            String lyrics = convertMelody(parts[3]);
            
            StringBuilder sb = new StringBuilder();
            for (int i=0; i<times; i++)
                sb.append(lyrics.charAt(i % lyrics.length()));
            String fullLyrics = sb.toString();
            if (fullLyrics.contains(m) && times > maxTime)
            {
                answer = title;
                maxTime = times;
            }
        }
        return answer;
    }
}

C#과 같은 음악을 다른 수로 치환해주며, 비교를 하니까 답이 됐다.

시간 같은 경우도 생각안하고 제출했는데 20, 27,28에서 오류가 나서 times maxTime을 비교했다.

더보기

문제 설명

n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.

송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.


제한사항
  • n은 2 이상 100 이하인 자연수입니다.
  • wires는 길이가 n-1인 정수형 2차원 배열입니다.
    • wires의 각 원소는 [v1, v2] 2개의 자연수로 이루어져 있으며, 이는 전력망의 v1번 송전탑과 v2번 송전탑이 전선으로 연결되어 있다는 것을 의미합니다.
    • 1 ≤ v1 < v2 ≤ n 입니다.
    • 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다.

입출력 예nwiresresult
9 [[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]] 3
4 [[1,2],[2,3],[3,4]] 0
7 [[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]] 1

입출력 예 설명

입출력 예 #1

  • 다음 그림은 주어진 입력을 해결하는 방법 중 하나를 나타낸 것입니다.
  • 4번과 7번을 연결하는 전선을 끊으면 두 전력망은 각 6개와 3개의 송전탑을 가지며, 이보다 더 비슷한 개수로 전력망을 나눌 수 없습니다.
  • 또 다른 방법으로는 3번과 4번을 연결하는 전선을 끊어도 최선의 정답을 도출할 수 있습니다.

입출력 예 #2

  • 다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
  • 2번과 3번을 연결하는 전선을 끊으면 두 전력망이 모두 2개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

입출력 예 #3

  • 다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
  • 3번과 7번을 연결하는 전선을 끊으면 두 전력망이 각각 4개와 3개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

출처 : https://school.programmers.co.kr/learn/courses/30/lessons/86971

 

문제해결

'트리'형태와, '개수가 가능한 비슷하도록 나눈다'에서 BFS 혹은 DFS의 느낌을 받았다.

간선 하나를 끊어서 트리를 두개로 나누고, 각 트리의 노드 개수를 세는 작업이 먼저 필요하다.

그전에, 이 그래프를 구현하는 것이 중요한데, 해당 그래프는 무방향 그래프로, 각자의 선이 연결되게끔 하기 위해

` <List<List<Integer>> graph'로 각 인덱스마다 다른 인덱스와 연결되게끔 구현해줬다.

 

graph  ──▶ ArrayList (index로 접근)
              ├─ index 0: []
              ├─ index 1: [3]
              ├─ index 2: [3]
              ├─ index 3: [1, 2, 4]
              ├─ index 4: [3, 5, 6, 7]
              ├─ ...

 

 

✅ BFS로 푸는 기본 흐름:

1. wires 배열에서 하나씩 간선을 빼고

2. 나머지 간선으로 그래프를 구성

3. BFS로 한 쪽 덩어리의 노드 개수 세기

4. 나머지는 n - count

5. 둘의 차이의 절댓값을 구해서 최소값 갱신

package study;

//무방향그래프공부
//전력망을 둘로 나누기

import java.util.*;

public class Sol64 {
	static boolean[] visited;

	public static int bfs(int start, List<List<Integer>> graph)
	{
		Queue<Integer> queue = new LinkedList<>();
		queue.offer(start);
		visited[start] = true;
		int cnt = 1;
		while (!queue.isEmpty())
		{
			int now = queue.poll();
			for (int next : graph.get(now)){
				if (!visited[next])
				{
					visited[next] = true;
					queue.offer(next);
					cnt++;
				}
			}
		}
		return cnt;
	}

	public static int solution(int n, int[][] wires)
	{
		int ans = -1;
		List<List<Integer>> graph = new ArrayList<>();
		for (int i=0; i<=n; i++)
			graph.add(new ArrayList<>());
		for (int [] wire : wires)
		{
			int a = wire[0];
			int b = wire[1];
			graph.get(a).add(b);
			graph.get(b).add(a);
		}
		int min = Integer.MAX_VALUE;
		for (int i=0; i<wires.length; i++)
		{
			int a = wires[i][0];
			int b = wires[i][1];
			graph.get(a).remove(Integer.valueOf(b));
			graph.get(b).remove(Integer.valueOf(a));
			visited = new boolean[n + 1];
			int temp = bfs(a, graph);

			int other = n - temp;
			min = Math.min(min, Math.abs(temp - other));

			graph.get(a).add(b);
			graph.get(b).add(a);
		}

		return min;
	}


	public static void main(String[] args) {
		int[][] arr = {{1,3},{2,3},{3,4},{4,5},{4,6},{4,7},{7,8},{7,9}};
		System.out.println(solution(9, arr));
	}

}

 

- 문제 예시처럼, 간선을 제외했다가 비교하는 식으로 풀었다.

- BFS 탐색용 큐를 구현하였다.

- 연결을 제거했다가 복원하는 작업을 거쳤다.

해당 부분을 똑같이 dfs로도 구현했다.

 

package study;

import java.io.*;
import java.util.*;

//dfs버전

public class Sol64_1 {

	public static int dfs(int node, List<List<Integer>> graph, boolean[] visited)
	{
		visited[node] = true;
		int cnt = 1;
		for (int next: graph.get(node))
		{
			if (!visited[next])
				cnt += dfs(next, graph, visited);
		}
		return cnt;
	}



	public static int solution(int n, int [][] wires)
	{
		int cnt = 0;
		List<List<Integer>> graph = new ArrayList<>();
		for (int i=0; i<=n; i++)
			graph.add(new ArrayList<>());

		for (int [] wire: wires)
		{
			int a = wire[0];
			int b = wire[1];
			graph.get(a).add(b);
			graph.get(b).add(a);
		}
		int min = Integer.MAX_VALUE;

		for (int [] wire: wires)
		{
			int a = wire[0];
			int b = wire[1];

			graph.get(a).remove(Integer.valueOf(b));
			graph.get(b).remove(Integer.valueOf(a));

			boolean []visited = new boolean[n + 1];
			int temp = dfs(a, graph, visited);
			int temp_other = n - temp;
			int diff = Math.abs(temp - temp_other);
			min = Math.min(min, diff);
			graph.get(a).add(b);
			graph.get(a).add(b);
			graph.get(b).add(a);

		}
		return min;
	}


	public static void main(String[] args) {
		int[][] arr = {{1,3},{2,3},{3,4},{4,5},{4,6},{4,7},{7,8},{7,9}};
		System.out.println(solution(9, arr));
	}
}

 

- bfs와 풀이 방식은 같다. 

'Algorithm' 카테고리의 다른 글

프로그래머스 Level2 [3차] 방금 그곡 JAVA  (0) 2025.04.03

+ Recent posts