Search
Duplicate
📒

[Programmers] 11-1. 광고 삽입

상태
완료
수업
Algorithm Solving
주제
Programmers
4 more properties
참고

문제해설

NOTE
사람들이 가장 많이 보는 광고시간대를 고르자!

문제 로직고민

NOTE
사람들이 영상을 본 시작 시간대에 광고를 배치했을때 최대값이면 결과가 나오지 않을까?
예제 테스트케이스는 모두 통과했던 생각이었다.
광고 시작시간에 놔둔다는것은, 겹치는 경우가 많다는 의미이고 그만큼 많이 본다고 생각했다.
만약 전체 플레이타임을 벗어난다면 그만큼 조정해주는 로직을 추가했다.
하지만 다시 생각해보니 될리가 없었다…
질문하기 참고하고 다시 풀이진행, 전체시간 100시간은 36만의 값으로 브루트포스로 가능!
36만크기의 배열에, 구간합을 모두 구한다.
이후 1초마다 옮기면서 광고시간 범위내에서 최대 시청시간값을 구한다.

작성코드

NOTE
import java.util.*; class Solution { public String solution(String play_time, String adv_time, String[] logs) { int pt = convertInt(play_time); int at = convertInt(adv_time); int log_cnt = logs.length; ArrayList<int[]> logList = new ArrayList<int[]>(); // 1. 시간값을 모두 숫자값으로 변환 for(int i=0; i<log_cnt; i++){ String[] s = logs[i].split("-"); int st = convertInt(s[0]); int et = convertInt(s[1]); int[] log = {st, et}; logList.add(log); } // 2. 시간이 빠른순으로 정렬 Collections.sort(logList, (a1,a2) -> a1[0] - a2[0]); // 3. 각 시청시간의 시작지점을 기준으로 광고배치를 했을때 가장 많이 보는경우를 구한다. int idx = 0; int cnt = 0; for(int i=0; i<log_cnt; i++){ int st = logList.get(i)[0]; int et = st + at; int temp = 0; for(int j=i; j<log_cnt; j++){ int[] log = logList.get(j); if(et < log[0]) break; // 광고 범위를 벗어난다. else if(et < log[1]) temp += et - log[0]; // 포함은 되어있으나 시청도중에 광고가 끊긴다. else temp += log[1] - log[0]; // 광고 범위안에 모든 시청시간이 포함된다. } if(cnt < temp) { cnt = temp; idx = i; } } String answer; if(logList.get(idx)[0] + at > pt){ answer = convertString(logList.get(idx)[0] - (logList.get(idx)[0] + at - pt)); } else{ answer = convertString(logList.get(idx)[0]); } return answer; } private int convertInt(String time){ String[] s = time.split(":"); return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); } private String convertString(int time){ int h = time / 3600; int m = (time % 3600) / 60; int s = time % 60; return String.format("%02d:%02d:%02d", h, m, s); } }
Java
복사
16.1 / 100.0
당연히 야매로 풀어서 안될줄알았는데 기본 테스트케이스가 통과해서 설랬다..
결과는 처참하다.
import java.util.*; class Solution { public String solution(String play_time, String adv_time, String[] logs) { int pt = convertInt(play_time); int at = convertInt(adv_time); int log_cnt = logs.length; int[] time = new int[pt+1]; // 1. 시간값을 모두 숫자값으로 변환 (로그는 최대 30만개) for(int i=0; i<log_cnt; i++){ String[] s = logs[i].split("-"); int st = convertInt(s[0]); int et = convertInt(s[1]); time[st]++; time[et]--; } // 2. 전체 시간을 누적합으로 계산해둔다. (최대 36만개) for(int i=1; i<time.length; i++){ time[i] += time[i-1]; } // 3.가장 구간합이 큰 구간을 구한다. (최대 36만개) int answer = 0; long interval_time = 0; // long으로 선언해야 17번 태케통과함 for(int i=0; i<at; i++){ // 최초 구간합 interval_time += time[i]; } long max = interval_time; // 9, 31번이 틀렸던 이유.. (초기 max를 0으로 냅둠) for(int i=0, j=at; j<pt; i++, j++){ // 1초씩 움직이며 투포인터 계산 interval_time += time[j]; interval_time -= time[i]; if(interval_time > max){ answer = i+1; max = interval_time; } } return convertString(answer); } private int convertInt(String time){ String[] s = time.split(":"); return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); } private String convertString(int time){ int h = time / 3600; int m = (time % 3600) / 60; int s = time % 60; return String.format("%02d:%02d:%02d", h, m, s); } }
Java
복사
정답코드!
약간의 힌트를 얻고나서 풀이를 다시 진행했다. 전체적인 흐름은 알았는데 중간중간 실수를 잡는데 오래 걸렸다.
17번 테스트케이스 : logs(최대 30만) * 시간최대범위(36만) == Integer 범위초과..
9, 31번 테스트케이스 : 초기 max값을 누적합으로 수정하지 않고 0으로 놔두는 경우.

다른사람 풀이

NOTE
import java.util.Arrays; class Solution { public String solution(String play_time, String adv_time, String[] logs) { int playTime = parseTime(play_time); int advTime = parseTime(adv_time); long playNums[] = new long[playTime+10]; for(String log : logs){ String splitted[] = log.split("-"); playNums[parseTime(splitted[0])]++; playNums[parseTime(splitted[1])]--; } for(int i = 0; i < playNums.length-1; i++) playNums[i+1] += playNums[i]; int startTime = 0; long timeSum = 0; long max = timeSum; long maxStartTime = 0; while(startTime+advTime <= playTime){ if(max < timeSum){ max = timeSum; maxStartTime = startTime; } timeSum -= playNums[startTime]; timeSum += playNums[startTime+advTime]; startTime++; } return String.format("%02d:%02d:%02d", maxStartTime/3600, (maxStartTime/60)%60, maxStartTime%60); } int parseTime(String time){ String splitted[] = time.split(":"); return Integer.parseInt(splitted[0])*3600 + Integer.parseInt(splitted[1])*60 + Integer.parseInt(splitted[2]); } }
Java
복사
깔끔한 풀이법.. (로직은 동일)