🖥️ CS/SW Expert 외의 Algorithms
HackerRank : Fraudulent Activity Notifications
한국의 메타몽
2023. 4. 6. 02:22
문제 링크
HackerRank : Fraudulent Activity Notifications (Click)
문제 요약
List<integer>
타입의expenditure
와 int타입의d
가 아래와 같이 주어진다.expenditure = [10,20,30,40,50] d = 3
- 중간값의 정의는 해당 글을 참고한다.
- 예를 들어 위와 같이 d가 3인 경우, n-3, n-2, n-1의 값중
중간값 * 2
이상의 값을 n번째 날이 가질 경우, 고객에게 알림을 보내줘야한다. - 10,20,30의 중간값은 20인데, 40의 경우 20*2 이상의 값을 가지므로 알림을 보내야한다.
- 20,30,40의 중간값은 30인데, 50의 경우 30*2 보다 값이 작으므로 알림을 보낼 필요가 없다.
- 때문에 위 예시에서 알림을 보내는 개수(정답)는 1이 된다.
문제 풀이
문제에서 언급된 아래의 제약 사항을 잘 확인해야 한다.
0 <= expenditure[i] <= 200
1일당 금액은 아무리 커도 0 ~ 200 사이인데, 이런 경우엔 계수정렬을 활용하는게 좋다.
(계수정렬 참고 : https://astrid-dm.tistory.com/48)
무턱대고 라이브러리에서 제공하는 기본 sort를 사용할 경우, 시간초과가 나기 딱 좋기 때문이다.
public static int activityNotifications(List<Integer> expenditure, int d) {
// Write your code here
int left = 0, right=d-1, ans = 0, mid = 0;
int[] temp = new int[201];
for(int i=0; i<d; i++) temp[expenditure.get(i)]++;
while(right < expenditure.size()-1){ // 윈도우 슬라이싱 (Windoe Slicing) 활용
mid = findMid(temp,d);
if(expenditure.get(right+1) >= mid) ans++;
temp[expenditure.get(left)]--;
left++;
right++;
temp[expenditure.get(right)]++;
}
return ans;
}
public static int findMid(int[] arr, int d) {
int temp = 0;
int idx = 0;
int point = d/2;
for(int i=0; i<arr.length; i++){
if(arr[i] != 0) idx += arr[i];
if(d%2 != 0){
if(idx > point){ // d가 홀수인 경우
return i*2;
}
} else { // d가 짝수인 경우
if(idx >= point && temp == 0) {
temp = i;
}
if(idx >= point+1) {
temp += i;
break;
}
}
}
return temp;
}
d가 짝수인 경우만 주의하면 되는데, 저렇게 짝수인 경우에만 케이스가 나뉘는 이유는 아래의 예시에서 설명될 수 있다.
case 1 : {1,2,2,3,3,3, 5} -> 가운데 2,3을 가져가야함
case 2 : {1,2,2,3,3,3,3,3, 7} -> 가운데 3,3,을 가져가야함
시간복잡도
O(n * 201)