Skip to content

Commit 52ac160

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents d4439f8 + 8246eb1 commit 52ac160

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2094
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def longestConsecutive(self, nums: List[int]) -> int:
7+
return self.solveWithDict(nums)
8+
9+
"""
10+
Runtime: 486 ms (Beats 40.61%)
11+
Time Complexity:
12+
- nums 배열 조회하며 연산에 O(n)
13+
- 크기가 n인 node_dict.items()을 조회, visited에 의해 각 노드당 한 번만 방문,
14+
- visited가 set이므로 갱신 및 확인에 O(1)
15+
- 2개 항에 대해 max 연산하므로 O(2)로, 총 O(n)
16+
> O(n) + O(n) ~= O(n)
17+
18+
Memory: 44.62 MB (Beats 5.00%)
19+
Space Complexity: O(n)
20+
- value가 크기 2짜리 배열이고 key가 최대 n인 dict 변수 사용에 O(2n)
21+
- 최대 크기가 n인 visited 사용에 O(n)
22+
> O(2n) + O(n) ~= O(n)
23+
"""
24+
def solveWithDict(self, nums: List[int]) -> int:
25+
node_dict = {}
26+
for num in nums:
27+
curr_node = [num, num]
28+
if num - 1 in node_dict:
29+
prev_node = node_dict[num - 1]
30+
curr_node[0] = prev_node[0]
31+
prev_node[1] = curr_node[1]
32+
if num + 1 in node_dict:
33+
post_node = node_dict[num + 1]
34+
curr_node[1] = post_node[1]
35+
post_node[0] = curr_node[0]
36+
node_dict[num] = curr_node
37+
38+
max_length = 0
39+
visited = set()
40+
for key, (prev_key, post_key) in node_dict.items():
41+
while prev_key not in visited and prev_key in node_dict:
42+
visited.add(prev_key)
43+
prev_key = node_dict[prev_key][0]
44+
while post_key not in visited and post_key in node_dict:
45+
visited.add(post_key)
46+
post_key = node_dict[post_key][1]
47+
curr_length = post_key - prev_key + 1
48+
max_length = max(max_length, curr_length)
49+
50+
return max_length
51+
52+
53+
class _LeetCodeTestCases(TestCase):
54+
def test_1(self):
55+
nums = [100, 4, 200, 1, 3, 2]
56+
output = 4
57+
self.assertEqual(Solution.longestConsecutive(Solution(), nums), output)
58+
59+
def test_2(self):
60+
nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
61+
output = 9
62+
self.assertEqual(Solution.longestConsecutive(Solution(), nums), output)
63+
64+
65+
if __name__ == '__main__':
66+
main()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* 풀이
3+
* - 주어진 배열 `nums`로 set `s`를 만듭니다
4+
* - `nums`를 조회하는데, 현재 조회 중인 `num`에 대하여 `num - 1`이 `s`에 포함되지 않는 경우만 while문을 실행하여 subsequence의 길이를 측정합니다
5+
* - `num - 1`이 `s`에 포함되지 않는다는 것은 `num`이 해당 subsequence의 첫 수임을 뜻합니다
6+
*
7+
* Big-O
8+
* - N: 주어진 배열 `nums`의 길이
9+
*
10+
* - Time complexity: O(N)
11+
* - 이중 반복문의 구조를 가졌지만, 조건문때문에 각 원소를 한 번씩만 조회합니다
12+
*
13+
* - Space complexity: O(N)
14+
* - `nums`를 구성하는 원소가 모두 고유한 정수일 경우, `s`의 크기가 `nums`만큼 커질 수 있습니다
15+
*/
16+
17+
class Solution {
18+
public:
19+
int longestConsecutive(vector<int>& nums) {
20+
unordered_set<int> s(nums.begin(), nums.end());
21+
22+
int res = 0;
23+
for (int num : nums) {
24+
if (s.find(num - 1) != s.end()) continue;
25+
26+
int curr = num;
27+
int streak = 1;
28+
while (s.find(curr + 1) != s.end()) {
29+
++curr;
30+
++streak;
31+
}
32+
res = max(res, streak);
33+
}
34+
35+
return res;
36+
}
37+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""TC: O(n), SC: O(n)
2+
3+
아이디어:
4+
- nums 안에는 여러 consecutive sequence(이하 cs)가 존재할 것이다(길이 1인 것까지 포함).
5+
- 이 cs는 모두 제일 앞 숫자를 가지고 있다.
6+
- 제일 앞 숫자는 그 숫자 바로 앞에 숫자가 없다는 특징을 가지고 있다.
7+
- 즉, i가 제일 앞 숫자라면 i-1은 nums 안에 없다.
8+
- nums에서 제일 앞 숫자를 찾은 다음, 이 숫자부터 뒤로 이어지는 cs를 찾아서 길이를 구할 수 있다.
9+
- cs의 길이 중 제일 긴 것을 찾아서 리턴하면 된다.
10+
11+
SC:
12+
- set(nums)에서 O(n).
13+
- 위 set에서 모든 아이템을 돌면서 i-1이 set 안에 포함되지 않는 i를 찾아서 리스트로 만들때 O(n).
14+
- 총 O(n).
15+
16+
TC:
17+
- set(nums)에서 O(n).
18+
- 위 set에서 모든 아이템을 돌면서 i-1이 set 안에 포함되지 않는 i를 찾는 데에 O(n).
19+
- 각 cs의 제일 앞 숫자부터 이어지는 숫자들이 set 안에 있는지 체크하는 데에 총 O(n).
20+
- 총 O(n).
21+
"""
22+
23+
24+
class Solution:
25+
def longestConsecutive(self, nums: List[int]) -> int:
26+
s = set(nums) # TC:O(n), SC:O(n)
27+
seq_start_candidate = [i for i in s if i - 1 not in s] # TC:O(n), SC:O(n)
28+
sol = 0
29+
30+
# 아래의 for문 내에서는 s에 속한 아이템에 한 번씩 접근한다. TC:O(n)
31+
for i in seq_start_candidate:
32+
seq_len = 1
33+
while i + seq_len in s:
34+
seq_len += 1
35+
sol = max(seq_len, sol)
36+
return sol
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// time complexity: O(n)
2+
// spatail complexity: O(n)
3+
4+
class Solution {
5+
public:
6+
int longestConsecutive(vector<int>& nums) {
7+
unordered_set<int> exisingNum(nums.begin(), nums.end());
8+
9+
int maxLength = 0, length;
10+
for(int num : nums) {
11+
if(exisingNum.find(num - 1) != exisingNum.end()) {
12+
continue;
13+
}
14+
15+
length = 1;
16+
while(exisingNum.find(num + length) != exisingNum.end()) {
17+
++length;
18+
}
19+
20+
maxLength = max(maxLength, length);
21+
}
22+
23+
return maxLength;
24+
}
25+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {number}
4+
*/
5+
var longestConsecutive = function(nums) {
6+
if (nums.length === 0) return 0;
7+
8+
const numSet = new Set(nums);
9+
let maxSequenceLength = 0;
10+
11+
for (const num of numSet) {
12+
if (!numSet.has(num - 1)) {
13+
let currentNum = num;
14+
let currentLength = 1;
15+
16+
while (numSet.has(currentNum + 1)) {
17+
currentNum++;
18+
currentLength++;
19+
}
20+
21+
maxSequenceLength = Math.max(maxSequenceLength, currentLength);
22+
}
23+
}
24+
25+
return maxSequenceLength;
26+
};
27+
28+
console.log(longestConsecutive([100, 4, 200, 1, 3, 2]));
29+
console.log(longestConsecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1]));
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* @description
3+
* brainstorming:
4+
* priority queue + result counting that priority queue was pop
5+
*
6+
* time complexity: O(n log n)
7+
* space complexity: O(n)
8+
*/
9+
var longestConsecutive = function (nums) {
10+
const queue = new CustomQueue();
11+
let [count, before, answer] = [0, null, 0];
12+
13+
nums.forEach((n) => queue.insert(n));
14+
15+
if (queue.size === 0) return count;
16+
17+
[count, before, answer] = [1, queue.remove(), 1];
18+
19+
while (queue.size) {
20+
const current = queue.remove();
21+
22+
if (before === current) continue;
23+
24+
count = before + 1 === current ? count + 1 : 1;
25+
before = current;
26+
answer = Math.max(answer, count);
27+
}
28+
29+
return answer;
30+
};
31+
32+
class Node {
33+
constructor(value) {
34+
this.value = value;
35+
}
36+
}
37+
38+
class CustomQueue {
39+
constructor() {
40+
this.items = new Map();
41+
this.size = 0;
42+
}
43+
44+
parentIndex(index) {
45+
return Math.floor((index - 1) / 2);
46+
}
47+
48+
leftChildIndex(index) {
49+
return 2 * index + 1;
50+
}
51+
52+
rightChildIndex(index) {
53+
return 2 * index + 2;
54+
}
55+
56+
heapifyUp() {
57+
let index = this.size - 1;
58+
59+
while (index > 0) {
60+
const parentIndex = this.parentIndex(index);
61+
const parent = this.items.get(parentIndex);
62+
const current = this.items.get(index);
63+
64+
if (parent.value <= current.value) break;
65+
66+
this.items.set(this.parentIndex(index), current);
67+
this.items.set(index, parent);
68+
69+
index = parentIndex;
70+
}
71+
}
72+
73+
heapifyDown() {
74+
let index = 0;
75+
76+
while (this.leftChildIndex(index) < this.items.size) {
77+
let smallestIndex = this.leftChildIndex(index);
78+
let rightIndex = this.rightChildIndex(index);
79+
const current = this.items.get(index);
80+
81+
if (
82+
rightIndex < this.size &&
83+
this.items.get(rightIndex).value < this.items.get(smallestIndex).value
84+
) {
85+
smallestIndex = rightIndex;
86+
}
87+
88+
if (current.value <= this.items.get(smallestIndex).value) break;
89+
this.items.set(index, this.items.get(smallestIndex));
90+
this.items.set(smallestIndex, current);
91+
index = smallestIndex;
92+
}
93+
}
94+
95+
insert(value) {
96+
const index = this.size;
97+
const node = new Node(value);
98+
this.items.set(index, node);
99+
this.size++;
100+
this.heapifyUp();
101+
}
102+
103+
remove() {
104+
if (this.size === 0) return null;
105+
106+
const root = this.items.get(0);
107+
this.items.set(0, this.items.get(this.size - 1));
108+
this.items.delete(this.size - 1);
109+
this.size--;
110+
111+
this.heapifyDown();
112+
return root.value;
113+
}
114+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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

Comments
 (0)