Skip to content

Commit 0f9f438

Browse files
authored
Merge pull request #2387 from gyeo-ri/main
[gyeo-ri] WEEK 01 solutions
2 parents 4759a12 + e917292 commit 0f9f438

2 files changed

Lines changed: 120 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
[결과 요약]
3+
# 재시도횟수: 4회
4+
1. 모든 문자열 한 번씩 순회하기(실패)
5+
- 단순 순회가 아니라 실패 시 직전의 중복 문자열 위치를 찾아야 해서 단순 순회로는 처리가 불가함
6+
2. 문자열 상태를 기록하고, 중복된 문자열이 등장했을 때 기존 문자열을 split 하여 다시 순회를 시작하는 방법(힌트 없이 성공한 방식)
7+
- 연산 결과는 동일하지만 복잡도가 O(n^2)으로 효율적이지는 않음
8+
(3부터 구현 방식에 대한 힌트를 참조)
9+
3. Sliding Window를 구현(두 개의 포인터, Set)
10+
- 시간복잡도: O(n) / 공간복잡도: O(n)
11+
- 중복 발생 시 while문을 사용하여 중복된 문자가 등장하는 위치까지 순차 탐색(이전 문자열을 제거)
12+
4. Dict으로 (3)과 같은 로직을 구현
13+
- 시간복잡도: O(n) / 공간복잡도: O(n)이지만 dict을 사용하므로 시간 절약 / 메모리는 약간 더 사용함
14+
- 인덱스를 순차로 탐색하는 것이 아니라 dict에서 바로 조회하는 방식
15+
16+
17+
"""
18+
19+
20+
class Solution:
21+
def lengthOfLongestSubstring(self, s: str) -> int:
22+
used_characters = dict()
23+
longest_length = 0
24+
start_idx = 0
25+
26+
for end_idx, c in enumerate(s):
27+
if c in used_characters:
28+
duplicated_idx = used_characters[c]
29+
if duplicated_idx >= start_idx:
30+
start_idx = duplicated_idx + 1
31+
32+
used_characters[c] = end_idx
33+
longest_length = max(longest_length, end_idx - start_idx + 1)
34+
35+
return longest_length
36+
37+
38+
"""
39+
# Set을 이용한 구현(Dict와 복잡도 상으로는 큰 차이 없음)
40+
class Solution:
41+
def lengthOfLongestSubstring(self, s: str) -> int:
42+
used_characters = set()
43+
longest_length = 0
44+
start_idx = 0
45+
46+
for end_idx in range(len(s)):
47+
while s[end_idx] in used_characters:
48+
used_characters.remove(s[start_idx])
49+
start_idx += 1
50+
51+
used_characters.add(s[end_idx])
52+
# 속도는 if문보다 약간 느리지만 가독성 크게 개선
53+
longest_length = max(longest_length, end_idx - start_idx + 1)
54+
55+
return longest_length
56+
"""
57+
58+
if __name__ == "__main__":
59+
solution = Solution()
60+
61+
test_cases = [
62+
("abcabcbb", 3),
63+
("bbbbb", 1),
64+
("pwwkew", 3),
65+
("a", 1),
66+
("bb!1 2@!#$1%3", 9),
67+
]
68+
for idx, cases_ in enumerate(test_cases):
69+
s, answer = cases_
70+
result = solution.lengthOfLongestSubstring(s)
71+
assert (
72+
answer == result
73+
), f"Test Case {idx} Failed: Expected {answer}, Got {result}"

two-sum/gyeo-ri.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
[결과 요약]
3+
# 재시도횟수: 3회
4+
1. 배열의 모든 경우의 수 계산하기
5+
- 시간복잡도 O(n^2)
6+
2. 전체 반복하지 않고 인덱스 기준 뒤만 반복하기
7+
- O(n^2)이지만 약간 더 효율적
8+
3. 딕셔너리(Map) 사용
9+
- 시간복잡도: O(n) / 공간복잡도: O(n)
10+
- 딕셔너리 자체는 빨리 떠올렸으나 Key 중복이 될 수 있다고 잘못 판단하여 시간을 오래 소모
11+
- 실제로 하나의 숫자는 최대 두 번까지 사용되어 구조 상 Key가 중복되지 않음
12+
"""
13+
14+
15+
class Solution:
16+
def twoSum(self, nums: list[int], target: int) -> list[int]:
17+
nums_dict = {}
18+
19+
for idx1, num1 in enumerate(nums):
20+
num2 = target - num1
21+
idx2 = nums_dict.get(num2)
22+
23+
if idx2 is None:
24+
nums_dict.update({num1: idx1})
25+
else:
26+
return [idx1, idx2]
27+
28+
raise Exception("Invalid nums and target")
29+
30+
31+
if __name__ == "__main__":
32+
test_cases = [
33+
([2, 7, 11, 15], 9, {0, 1}),
34+
([3, 2, 4], 6, {1, 2}),
35+
([3, 3], 6, {0, 1}),
36+
([-2, -3, 0, 3], 1, {0, 3}),
37+
([0, -5, 2, 6], -3, {1, 2}),
38+
([4, 7, 2, 0, 0], 0, {3, 4}),
39+
]
40+
41+
solution = Solution()
42+
for idx, case_ in enumerate(test_cases):
43+
nums, target, answer = case_
44+
result = solution.twoSum(nums, target)
45+
assert answer == set(
46+
result
47+
), f"Test Case {idx} Failed: Expected {answer}, Got {result}"

0 commit comments

Comments
 (0)