|
| 1 | +/* |
| 2 | +* 조건 |
| 3 | +* 연속된 수가 가장 긴 경우, 몇 번인지 구하기. 같은 값은 이어서 연결할 수 있음. |
| 4 | +* 시간복잡도는 O(n)이어야함 = nums 배열을 한번만 돌아서 구할 것, 정렬 메소드는 쓸 수 없음(O(nlogn)) |
| 5 | +* |
| 6 | +* 아이디어 |
| 7 | +* 시작지점과 끝나는 지점, 그 길이가 가장 긴 것을 구해야함 |
| 8 | +* 배열 값들을 한번만 체크할 수 있도록 배열을 돌면서 값을 set 자료구조에 저장해둔다 |
| 9 | +* 이때 set 사용하는 이유는, |
| 10 | +* 특정 값이 중복인 경우를 고려할 필요가 없기 때문 |
| 11 | +* |
| 12 | +* 다시 nums 배열을 돌면서 현재 값 직전값이나 이후값이 있는지, 앞뒤로 연속되는 수가 몇개가 있는지 체크한다 |
| 13 | +* 앞뒤로 연속되는 숫자의 개수로 새로운 배열을 만든다 |
| 14 | +* 새로 만들어진 배열 중 가장 큰 값을 리턴한다 |
| 15 | +
|
| 16 | +* 이렇게 했을때 leetcode 시간초과가 뜬다. |
| 17 | +* 중복계산 하는 부분을 줄여보자. |
| 18 | +* 왼쪽에 있는 값은 왼쪽값에서 체크를 할거라 미리 계산해줄 필요가 없다, 현재 값부터 오른쪽 값만 계산한다. |
| 19 | +* nums 배열을 돌면서 왼쪽값이 없는 경우만 오른쪽 값에 대해 길이를 계산한다 |
| 20 | +* 값에 대한 오른쪽 길이를 이미 계산한 적 있는 경우, memo된 값을 사용한다 |
| 21 | +* |
| 22 | +*/ |
| 23 | +function longestConsecutive(nums: number[]): number { |
| 24 | + // TC: O(n) |
| 25 | + // SC: O(n) |
| 26 | + const numSet: Set<number> = new Set(nums); |
| 27 | + |
| 28 | + // SC: O(n) |
| 29 | + const numLengthMemo: Map<number, number> = new Map(); |
| 30 | + let maxLength = 0; |
| 31 | + |
| 32 | + // TC: O(n) |
| 33 | + for (let n of nums) { |
| 34 | + if (!numSet.has(n - 1)) { |
| 35 | + let length = 1; |
| 36 | + |
| 37 | + if (numLengthMemo.has(n)) { |
| 38 | + length = numLengthMemo.get(n); |
| 39 | + maxLength = Math.max(maxLength, length); |
| 40 | + continue; |
| 41 | + } |
| 42 | + |
| 43 | + // TC: O(n) |
| 44 | + while (numSet.has(n + length)) { |
| 45 | + length++; |
| 46 | + } |
| 47 | + |
| 48 | + numLengthMemo.set(n, length); |
| 49 | + maxLength = Math.max(maxLength, length); |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + return maxLength; |
| 54 | +} |
| 55 | + |
| 56 | +function getNumCount(current: number, dict: Map<number, number>) { |
| 57 | + return dict.get(current) ?? 0; |
| 58 | +} |
| 59 | + |
| 60 | +// TC: O(n) |
| 61 | +// SC: O(n) |
0 commit comments