카테고리 없음

[JS 알고리즘&자료구조] 기준점과 이동 배열 패턴

발싸믹쏘스 2023. 11. 15. 00:09

기준점과 이동 배열 패턴은 '슬라이딩 윈도우 패턴' 이라고도 부르며 배열이나 문자열과 같은 일련의 데이터를 입력하거나 특정 방식으로 큰 데이터셋에 하위 집합을 찾을 때 유용하다.

아래는 기준점과 이동 배열 패턴을 사용하여 해결할 수 있는 문제이다.

/*
maxSubarraySum이라는 함수가 있다. 
이 함수는 배열과 숫자 하나를 매개 변수로 받으며 받은 숫자 만큼 연속된 숫자들의 가장 큰 합계를 찾는 함수이다. 
아래는 함수의 반환값들의 예시이다.
*/

maxSubarraySum([1,2,5,2,8,1,5], 2) // 10
maxSubarraySum([1,2,5,2,8,1,5], 4) // 17
maxSubarraySum([4,2,1,6], 1) // 6
maxSubarraySum([4,2,1,6,2], 4) // 13
maxSubarraySum([], 4) // null

문제를 해결하기 위해 우리는 우선 '창문'(윈도우)를 만들어야 한다. 창문은 단일 변수, 하위 배열 혹은 문자열이 될 수 있다. 이 창문을 조건에 따라 특정 방향으로 진행시키며 원하는 값을 찾아낸다. 우선 패턴을 사용하지 않는 풀이법부터 살펴보자.

function maxSubarraySum(arr, num) {
  if (num > arr.length) {
    return null;
  }
  
  let max = -Infinity;
  for (let i = 0; i < arr.length - num + 1; i ++) {
    temp = 0;
    for (let j = 0; j < num; j++) {
      temp += arr[i+j];
    }
    if (temp > max) {
      max = temp;
    }
  }
  
  return max;
}


위의 방법은 당연히 배열이 작을 때는 문제가 없으나 배열이 커지는 순간 엄청나게 큰 처리 속도를 가지게 된다. 빅오 표기법으로도 O(n²)의 시간 복잡도를 가지게 된다. 이제 슬라이딩 윈도우 패턴을 사용하여 위의 로직을 리팩토링해보자.

function maxSubarraySum(arr, num) {
  let maxSum = 0;
  let tempSum = 0;
  if (arr.length < num) return null;
  for (let i = 0; i < num; i++) {
  	maxSum += arr[i];
  }
  tempSum = maxSum;
  for (let i = num; i < arr.length; i++) {
    tempSum = tempSum - arr[i - num] + arr[i];
    maxSum = Math.max(maxSum, tempSum);
  }
  return maxSum;
}

위의 방법을 통해 원래는 반복문을 계속 돌면 num 만큼을 반복하여 합산을 진행해야했지만 이제는 맨 앞 인덱스에 있는 숫자를 빼고 마지막 인덱스의 다음 인덱스에 있는 숫자를 더하는 간단한 작업만으로 합산을 계속 비교해가면서 진행해나갈 수 있게 되었다. 이를 통해 우리는 O(n)의 시간 복잡도를 가진 로직으로 리팩토링도 성공적으로 수행해낸 것이다.