2024. 1. 16. 23:12ㆍ알고리즘
슬라이딩 윈도우
슬라이딩 윈도우는 일정 크기의 윈도우를 옆으로 밀면서 결과값을 도출해야할 때 사용하는 알고리즘이다.
백준 21921
찬솔이는 블로그를 시작한 지 벌써 일이 지났다.
요즘 바빠서 관리를 못 했다가 방문 기록을 봤더니 벌써 누적 방문 수가 6만을 넘었다.
찬솔이는 일 동안 가장 많이 들어온 방문자 수와 그 기간들을 알고 싶다.
찬솔이를 대신해서 일 동안 가장 많이 들어온 방문자 수와 기간이 몇 개 있는지 구해주자.
입력
첫째 줄에 블로그를 시작하고 지난 일수 와 가 공백으로 구분되어 주어진다.
둘째 줄에는 블로그 시작 일차부터 일차까지 하루 방문자 수가 공백으로 구분되어 주어진다.
출력
첫째 줄에 일 동안 가장 많이 들어온 방문자 수를 출력한다. 만약 최대 방문자 수가 0명이라면 SAD를 출력한다.
만약 최대 방문자 수가 0명이 아닌 경우 둘째 줄에 기간이 몇 개 있는지 출력한다.
1 | 4 | 2 | 5 | 1 |
예를 들어 다음과 같이 방문자 수가 주어지고 X값이 2라면,
2일동안 가장 많이 방문한 방문자 수와 그 기간을 구하는 문제이다.
완전탐색으로 접근을 한다면 다음과 같을 것이다.
1 + 4
4 + 2
2 + 5
5 + 1
색칠한 부분의 값들은 중복되어 더해지게 된다.
또한 방문자 수 N만큼 X가 루프문이 돌기 때문에 O(N*X) 만큼의 시간복잡도를 가지게 된다.
슬라이딩 윈도우를 사용하면 O(N)으로 효율성을 높일 수 있다.
1 | 4 | 2 | 5 | 1 |
1 | 4 | 2 | 5 | 1 |
1 | 4 | 2 | 5 | 1 |
1 | 4 | 2 | 5 | 1 |
X가 2이므로 2사이즈의 윈도우를 생성한다.
그리고 이 윈도우를 계속해서 밀면서 배열 끝까지 가면 된다.
이렇게 되면 배열의 사이즈만큼만 실행하게 되므로 시간복잡도를 줄일 수 있게된다.
코드
function solution(x, arr) {
const tmp = {};
let windowSum = 0;
let max = Number.MIN_SAFE_INTEGER;
for (let i = 0; i < arr.length; i++) {
windowSum += arr[i];
if (i >= x - 1) {
if (tmp[windowSum]) tmp[windowSum]++;
else {
tmp[windowSum] = 0;
tmp[windowSum]++;
}
windowSum -= arr[i - (x - 1)];
}
}
console.log(tmp);
max = Math.max(...Object.keys(tmp).map(Number));
if (max === 0) {
console.log('SAD');
} else {
console.log(max);
console.log(tmp[max]);
}
}
1 | 4 | 2 | 5 | 1 |
1 | 4 | 2 | 5 | 1 |
윈도우를 슬라이딩 할 때, 앞에 있는 수는 빼버리고 그 다음에 오는 수를 추가하는 규칙을 가지고 있다.
즉, 인덱스 기준 arr[2]를 추가한다면 arr[0]은 제거되어야한다.
이것을 수식으로 정리하면 i - ( k - 1 ) 에 위치하는 값을 빼고 i를 한 칸 옮긴 값을 더해주면 된다.
또 다른 규칙은 윈도우 사이즈만큼의 합을 구한 후,
윈도우를 슬라이딩 할 때는 옮기려는 값 - 지우려는 값을 기존의 합에 더해주면 된다.
'알고리즘' 카테고리의 다른 글
문자열 탐색 - 가장 짧은 문자거리 (0) | 2024.01.20 |
---|---|
구현 - 분수찾기 (1) | 2024.01.17 |
투 포인터 알고리즘 - 개념정리 (1) | 2024.01.16 |
브루트 포스 - 뒤집은 소수 (0) | 2024.01.15 |
브루트 포스 - 졸업 선물 (0) | 2024.01.12 |