본문 바로가기

LeetCode

2762. Continuous Subarrays / TypeScript

You are given a 0-indexed integer array nums. A subarray of nums is called continuous if:

  • Let i, i + 1, ..., j be the indices in the subarray. Then, for each pair of indices i <= i1, i2 <= j, 0 <= |nums[i1] - nums[i2]| <= 2.

Return the total number of continuous subarrays.

A subarray is a contiguous non-empty sequence of elements within an array.

 

Example 1:

Input: nums = [5,4,2,4]
Output: 8
Explanation: 
Continuous subarray of size 1: [5], [4], [2], [4].
Continuous subarray of size 2: [5,4], [4,2], [2,4].
Continuous subarray of size 3: [4,2,4].
Thereare no subarrys of size 4.
Total continuous subarrays = 4 + 3 + 1 = 8.
It can be shown that there are no more continuous subarrays.

 

Example 2:

Input: nums = [1,2,3]
Output: 6
Explanation: 
Continuous subarray of size 1: [1], [2], [3].
Continuous subarray of size 2: [1,2], [2,3].
Continuous subarray of size 3: [1,2,3].
Total continuous subarrays = 3 + 2 + 1 = 6.

 

출처 : https://leetcode.com/problems/continuous-subarrays/description/

 

풀이

 

function continuousSubarrays(nums: number[]): number {
    let sum = 0
    let start = 0
    let map = new Map()

    for(let end = 0; end < nums.length; end++) {
        map.set(nums[end], (map.get(nums[end]) || 0) + 1) // optimistically grow array

        // window is invalid, shrink the array from left to make valid
        while(Math.max(...map.keys()) - Math.min(...map.keys()) > 2) {
            let count = map.get(nums[start]) - 1
            if (count === 0) {
                map.delete(nums[start])
            } else {
                map.set(nums[start], count)
            }
            start++
        }

        // count the valid subarrays
        sum += (end - start + 1)
    }

    return sum
};

 

배열 nums에서 조건을 만족하는 "유효한" 연속 부분 배열(subarray)을 찾고, 그 부분 배열들의 개수를 구하는 문제를 해결하는 함수

 

 

단계별 동작 설명

초기화

  • sum = 0: 유효한 부분 배열의 개수를 저장
  • start = 0: 윈도우의 시작 인덱스를 의미
  • map = {}: 현재 윈도우 내 숫자의 빈도를 저장하는 맵

1. 첫 번째 반복 (end = 0)

  • 현재 숫자 nums[0] = 5이므로, map은 {5: 1}
  • 현재 윈도우는 [5]이며, 최댓값과 최솟값은 모두 5. 따라서 차이는 5 - 5 = 0이므로 조건을 만족
  • 현재 유효한 부분 배열의 개수는 end - start + 1 = 0 - 0 + 1 = 1
  • sum += 1로 현재 sum은 1

2. 두 번째 반복 (end = 1)

  • 현재 숫자 nums[1] = 4이므로, map은 {5: 1, 4: 1}
  • 현재 윈도우는 [5, 4]이며, 최댓값은 5, 최솟값은 4. 차이는 5 - 4 = 1이므로 조건을 만족
  • 현재 유효한 부분 배열의 개수는 end - start + 1 = 1 - 0 + 1 = 2
  • sum += 2로 현재 sum은 3

3. 세 번째 반복 (end = 2)

  • 현재 숫자 nums[2] = 2이므로, map은 {5: 1, 4: 1, 2: 1}
  • 현재 윈도우는 [5, 4, 2]이며, 최댓값은 5, 최솟값은 2. 차이는 5 - 2 = 3이므로 조건을 만족하지 않음.
  • 조건을 만족하게 하기 위해 start를 증가시켜 윈도우를 줄임.
    • nums[start] = 5이므로, map에서 5의 빈도를 1 감소
    • 결과적으로 map = {4: 1, 2: 1}
    • 이제 윈도우는 [4, 2]가 되고, 최댓값은 4, 최솟값은 2로 차이는 4 - 2 = 2이므로 조건을 만족
  • 현재 유효한 부분 배열의 개수는 end - start + 1 = 2 - 1 + 1 = 2
  • sum += 2로 현재 sum은 5.

4. 네 번째 반복 (end = 3)

  • 현재 숫자 nums[3] = 4이므로, map은 {4: 2, 2: 1}
  • 현재 윈도우는 [4, 2, 4]이며, 최댓값은 4, 최솟값은 2. 차이는 4 - 2 = 2이므로 조건을 만족
  • 현재 유효한 부분 배열의 개수는 end - start + 1 = 3 - 1 + 1 = 3
  • sum += 3로 최종적으로 sum은 8

최종 결과

조건을 만족하는 모든 유효한 부분 배열들의 개수는 sum = 8