티스토리 뷰
코딩테스트/알고리즘 & 자료구조 개념
[알고리즘 | JS] Sliding Window Pattern(기준점 간 이동 배열 패턴)
blueprint-12 2022. 4. 19. 20:30🍕Sliding Window 패턴이란?
-This pattern involves creating a window which can either be an array or number from one position to another.
-Depending on a certain condition, the window either increases or closes(and a new window is created)
-very useful for keeping track of a subset of data in an array/string etc...
- 배열이나 문자열과 같은 일련의 데이터를 입력하거나 특정 방식으로 연속적인 해당 데이터의 하위 집합을 찾는 경우에 유용하다. (규모가 큰 데이터 셋에서 데이터의 하위 집합을 추적하는 문제에 있어서 유용)
- 해당 패턴은 창문(window)을 하나 만들어야 하는데 이 창문은 단일 변수, 하위 배열 또는 필요한 경우 문자열이 될 수도 있다.
- 조건에 따라 창문을 이동시키며, 시작 위치는 보통 왼쪽 -> 오른쪽으로 이동( 보통, 창문(window)을 왼쪽 즉, 요소의 시작 위치, 또는 배열이나 문자열의 시작 위치에서 끝나는 위치로 이동 )한다.
- 반대로 오른쪽 -> 왼쪽으로 이동도 가능하며 중앙에서 시작하는 것도 가능하다.
예시를 통해서 알아보자.
An Example
인자(param)로 정수 배열과 n이라는 수를 취하는 maxSubarraySum 이라는 함수를 작성해라
-배열은 정렬할 필요없이 '정수'만 있으면 된다. (정렬 필요없음)
-두 번째 인자인 n을 전달하면 함수는 해당 배열의 연속된 요소의 가장 큰 합계를 계산하게 된다.
*n은 합계를 구하고자 하는 숫자의 개수
maxSubarraySum([1,2,4,2,8,1,5], 2) //10
위의 예시 코드를 설명하면, 2개의 연속된 값의 합이 가장 큰 것을 찾는 것 즉, 2,8의 합이 제일 크므로 10을 반환
▶naive solution 의 경우, 시간 복잡도: O(n^2)
/*
the result should be...
maxSubarraySum([1,2,4,2,8,1,5],2) //10
maxSubarraySum([1,2,5,2,8,1,5],4) //17
maxSubarraySum([4,2,1,6],1) //10
maxSubarraySum([4,2,1,6,2],4) //13
maxSubarraySum([], 4) // null
*/
//먼저 naive solution (비효율적이지만 작동은 하는 순진한 접근법)
//이중 for문으로 시간 복잡도는 O(n^2)임
//n은 합계를 구하고자 하는 숫자의 개수
function maxSubarraySum(arr, num) {
if (num > arr.length) {
return null;
}
//배열이 모두 음수로 구성되어 있다면 가장 큰 합은 여전히 음수일 것임
//이처럼 양수로만 작업을 하지 않는한 0에서 시작하는 것은 전혀 도움이 되지 않기 때문에
//0대신 -infinity로 설정한 것이다.
let max = -Infinity;
//i가 순회하는 범위는 배열의 끝까지 도달하는 것이 아니라 -num + 1을 한다.
for (let i = 0; i < arr.length - num + 1; i++) {
//temp에는 각 루프의 합계가 저장된다.
//n개의 수를 더해서 현재의 max보다 크다면 max가 temp가 되도록 바꿔준다.
let temp = 0;
for (let j = 0; j < num; j++) {
//arr[i + j]는, i에서 시작하여 i + j를 수행하면 j의 위치(index)가 옆으로 한 자리 이동하는데,
//num이 3일때, 세 가지 숫자를 더하는 방법이라고 보면 된다.
//그냥 단순하게 생각하면 2중 for 문이니까 i가 한번 카운트되면,
//j라는 변수가 index를 3개 순회하면서 그 값을 temp에 더하는 것
temp += arr[i + j];
}
//만일 temp가 max보다 큰 경우에 max가 temp와 같도록 해준다.
if (temp > max) {
max = temp; // 새 값으로 max를 바꾸는 것(현재 값보다 더 큰 값을 만났으니 update)
}
//결과값을 확인해보기위해 콘솔로그
console.log(temp, max);
}
return max;
}
console.log(maxSubarraySum([2, 3, 64, 5, 2, 4, 1], 3));
/*
풀이:
n이 3일 때,
아래와 같이 3개를 연산하여 합계를 냄
2, 3, 64 = 69 max는 69
3, 64, 5 = 72 max는 72
64, 5, 2 = 71 max는 이전값 그대로 72
5, 2, 4 = 11 max는 그대로 72
2, 4, 1 // 여기서 '2'가 마지노선으로 3개를 연산할 수 있는 곳이 되므로 arr.length - num(3) + 1
// 7 max는 그대로 72
temp, max
69 69
72 72
71 72
11 72
7 72
결과: 72
*/
코드 해설
- 맨 처음 if절은 num이 배열의 길이를 넘어가는 경우 null을 반환하도록 하여 입력값에 제한을 둔다.
- let max = - Infinity; 코드는 배열의 모든 값이 음수로 구성되어 있다면 가장 큰 합이 여전히 음수일 것을 고려하여 세팅한 것 배열에 모든 값들이 양수가 아닌 이상 초기값을 0으로 설정하는 것은 도움이 되지 않는다.
- arr.length -num + 1 i가 순회하는 범위는 배열의 끝까지 도달하는 것이 아니라 num에 해당하는 값 + 1이다. 예로 n이 3이라면 3가지 값을 더해야하기 때문에 최대로 도달할 수 있는 곳이 '배열전체길이' - 3 + 1 이 되는 것이다.
- let temp = 0; temp는 n개의 값을 더한 값이 들어가는 공간이다. 0으로 초기화해준다.
- 내부 for문 (let j = 0; j < num; j++){ //중략 } 3개의 값을 차례대로 더하여 temp에 담아주는 작업을 한다.
- if(temp > max) { max = temp;} temp가 max보다 큰 경우에 max의 값을 temp의 값으로 업데이트해준다.
- for문을 빠져나오면 return max 를 통해 가장 큰 값을 함수의 결과값으로 리턴해준다.
▶위의 코드를 리팩토링한 코드( 슬라이딩 미러 패턴을 적용)
-시간 복잡도가 O(n^2) -> O(n) 선형타임으로 된다.
function reFMaxSubarraySum(arr, num) {
let maxSum = 0;
let tempSum = 0;
//합계가 유효하지 않은 배열이고 숫자가 너무 크면 null 반환
if (arr.length < num) return null;
//첫번째 maxSum을 만든다.
for (let i = 0; i < num; i++) {
maxSum += arr[i];
}
tempSum = maxSum;
for (let i = num; i < arr.length; i++) {
//아래의 코드가 sliding window 패턴적용: 배열 값에 하나를 빼고 하나를 더하는 것
tempSum = tempSum - arr[i - num] + arr[i];
maxSum = Math.max(maxSum, tempSum); // Math.max()는 더 큰 값을 취하는 메소드이다.
//naive solution처럼 if문을 사용해도된다.
//tempSum이 maxSum보다 크면 maxSum을 갱신해준다.
console.log(tempSum, maxSum);
}
return maxSum;
}
reFMaxSubarraySum([2, 3, 4, 51, 5, 2, 3, 6, 5], 3);
console.log(reFMaxSubarraySum([2, 3, 4, 51, 5, 2, 3, 6, 5], 3));
'코딩테스트 > 알고리즘 & 자료구조 개념' 카테고리의 다른 글
[알고리즘 | JS] 재귀함수에 대해 알아보자! (호출스택, 스택오버플로우) (0) | 2022.04.23 |
---|---|
[알고리즘 | JS] 분할과 정복 패턴( Divide and Conquer) (0) | 2022.04.23 |
[알고리즘 | JS] 다중 포인터(Multiple pointers)패턴 (0) | 2022.04.19 |
[알고리즘 | JS] 문제 해결 패턴 소개, 빈도 카운터(Frequency Counter) (0) | 2022.04.16 |
[알고리즘] 문제 해결법(Algorithms and Problem Solving Pattersn) (0) | 2022.04.14 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- aspect-ratio
- ~ ^
- nvm 설치순서
- tilde caret
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- 프리렌더링확인법
- getServerSideProps
- fs모듈 넥스트
- float 레이아웃
- text input pattern
- nvm경로 오류
- 프리온보딩 프론트엔드 챌린지 3월
- 타입스크립트 장점
- 항해99프론트후기
- 원티드 3월 프론트엔드 챌린지
- D 플래그
- grid flex
- 항해99프론트
- 원티드 프리온보딩 FE 챌린지
- 타입스크립트 DT
- 형제 요소 선택자
- getStaticPaths
- reactAPI
- && 셸 명령어
- Prittier
- 항해99추천비추천
- is()
- 원티드 FE 프리온보딩 챌린지
- 부트캠프항해
- 틸드와 캐럿
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
글 보관함