Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[haklee] week 7 #484

Merged
merged 2 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions longest-substring-without-repeating-characters/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""TC: O(n), SC: O(n)

아이디어:
투포인터로 문자열의 시작, 끝 인덱스를 관리한다. 그리고 문자열 안에 있는 문자를 set으로 관리한다.
- 시작~끝 사이에 모든 문자가 서로 다르면 끝 인덱스를 하나 뒤로 옮긴다.
- 새로운 문자열의 제일 끝에 있는 문자가 혹시 set 안에 있으면 시작 인덱스를 뒤로 옮기는 작업을
해당 문자랑 같은 문자가 나올 때까지 진행한다. 즉, 끝을 고정하고 앞을 계속 옮겨서 새로운 문자열에
있는 모든 문자들이 다른 문자가 되도록 만든다.
- e.g.) abcdefd -> abcdefd
^ ^ ^ ^
s e s e
- 위의 과정을 계속 반복하면서 문자열의 최대 길이 값을 갱신한다.

SC:
- 새로운 문자열의 시작과 끝 인덱스 값을 관리하는 데에 O(1).
- 새로운 문자열 안에 들어있는 문자를 set으로 관리하는 데에 최악의 경우 n개의 문자가 모두 다를때 O(n).
- 최대 문자열 길이를 관리하는 데에 O(1).
- 종합하면 O(n).

TC:
- s, e는 모두 문자열의 인덱스를 나타내므로 s, e값을 아무리 많이 업데이트 해도 각가 문자열 길이보다
많이 업데이트 할 수는 없다. 즉, O(n).
- set에서 특정 문자가 들어있는지 체크하고 set에 문자를 더하거나 제거하는 데에 O(1). 이 작업을 아무리
많이 해도 s, e를 업데이트 하는 회수 만큼 진행하므로 총 O(n).
- 최대 문자열 길이를 업데이트 하는 데에 O(1). 이 또한 아무리 많이 진행해도 O(n).
- 종합하면 O(n).
"""


class Solution:
def lengthOfLongestSubstring(self, string: str) -> int:
if len(string) < 1:
return 0
s = e = 0
letter_set = set([string[0]])
sol = 1
while True:
e += 1
if e == len(string):
break

if string[e] in letter_set:
while True:
letter_set.discard(string[s])
if string[s] == string[e]:
break
s += 1
s += 1
letter_set.add(string[e])
sol = max(len(letter_set), sol)
return sol
41 changes: 41 additions & 0 deletions number-of-islands/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""TC: O(m * n), SC: O(m * n)

아이디어:
- 특정 칸이 1일 경우 이와 같은 섬 안에 있는 모든 칸들을 0으로 바꿔주는 `remove_ground` 함수 구현.
- grid 내의 모든 칸들을 돌면서 `remove_ground`가 몇 번 최초 호출(즉, 재귀 호출 아님) 되었는지
세면 전체 섬이 몇 개 있는지 찾을 수 있다.

SC:
- 모든 칸이 전부 1일 경우 remove_ground의 호출 스택 깊이가 m*n이 된다. 즉, O(m * n).

TC:
- 각 노드는 최대 5번씩 접근될 수 있다.
- 이웃한 칸에서 remove_ground 하면서 접근
- 최외곽에서 해당 칸이 1인지 체크하면서 접근
- 접근하고 나서 하는 연산이 O(1).
- 해당 칸의 값이 1인지 체크하는 데에 O(1).
- check_inside 연산을 4번 할 수 있는데 각각 O(1).
- 종합하면 O(1).
- 종합하면 O(m * n).
"""


class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
minx, miny, maxx, maxy = 0, 0, len(grid[0]) - 1, len(grid) - 1

def remove_ground(i, j):
haklee marked this conversation as resolved.
Show resolved Hide resolved
if minx <= j <= maxx and miny <= i <= maxy and grid[i][j] == "1":
grid[i][j] = "0"
remove_ground(i - 1, j)
remove_ground(i + 1, j)
remove_ground(i, j - 1)
remove_ground(i, j + 1)

sol = 0
for i in range(maxy + 1):
for j in range(maxx + 1):
if grid[i][j] == "1":
sol += 1
remove_ground(i, j)
return sol
28 changes: 28 additions & 0 deletions reverse-linked-list/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""TC: O(n), SC: O(1)

아이디어:
첫 아이템부터 차례대로 next로 넘어가면서 직전에 보았던 노드를 next에 넣어준다.

SC:
- 직전 노드를 관리한다. O(1).

TC:
- 모든 노드에 대해 직전 노드를 next에 대입한다.
- 그 외에 다른 연산도 O(1). 코드 참조.
- 종합하면 O(n).
"""


# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev, cur = None, head
while cur:
next = cur.next
cur.next = prev
prev, cur = cur, next
return prev
38 changes: 38 additions & 0 deletions set-matrix-zeroes/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""TC: O(m * n), SC: O(m + n)

아이디어:
모든 칸을 훑으면서 어떤 row, column을 0으로 바꿔줘야 하는지 찾은 다음 0으로 바꾸는 시행을 한다.

SC:
- 바꿔야 하는 column, row를 set으로 관리. 각각 O(m), O(n)이므로 종합하면 O(m + n).

TC:
- 모든 칸을 돌면서 어떤 column과 row를 0으로 바꿔야 하는지 체크한다. O(m * n).
- 0으로 바꿔야 하는 모든 column을 0으로 바꾼다. 모든 column을 다 0으로 바꿔야 할 경우 모든 칸에
접근해서 0을 넣어주어야 하므로 O(m * n).
- row도 column과 똑같이 접근 가능하다. O(m * n).
- 종합하면 O(m * n).
"""


class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
m, n = len(matrix), len(matrix[0])
col_to_change, row_to_change = set(), set()

for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
col_to_change.add(i)
row_to_change.add(j)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정말 티끌같은 이야기지만, 여기 라인브레이크 하나 있으면 심신이 조금 안정될 것 같습니다..!! 🥺

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가했습니다!


for i in col_to_change:
for j in range(n):
matrix[i][j] = 0

for j in row_to_change:
for i in range(m):
matrix[i][j] = 0
31 changes: 31 additions & 0 deletions unique-paths/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""TC: O(m + n), SC: O(1)

아이디어:
오른쪽으로 가는 회수 m-1, 아래로 가는 회수 n-1을 섞을 수 있는 방법의 수를 구하면 된다.
즉, m+n-2회의 이동 중 m-1개를 뽑아서 오른쪽으로 가고, 나머지를 아래로 가면 된다.
즉, (m+n-2)C(m-1)을 계산하면 된다.

큰 수 연산이 가능한 언어를 사용하면 nCk = n! / (k! * (n - k)!) 값을 계산하면 된다.
파이썬의 math.comb 함수는 아래와 같이 작동한다.
(ref: https://docs.python.org/ko/3/library/math.html#math.comb)
- math.comb(n, k)을 계산하면 k <= n이면 n! / (k! * (n - k)!)로 평가되고, k > n이면 0으로 평가됩니다.
이 함수를 써서 나온 결과값을 그대로 반환하자.

SC:
- 곱셈, 나눗셈 연산 결과 값 관리. O(1).
- 아주 큰 숫자를 다룰 경우 이렇게 보면 안 될 수도 있지만, 문제 조건을 보아하니 int64 범위 내에서
곱셈과 나눗셈 연산 값들이 모두 처리되는 것으로 보인다. 즉, SC가 그리 중요하지는 않다.

TC:
- (m+n-2)C(m-1) = (m+n-2)! / (m-1)! * (n-1)!
- 각 곱셈 값을 구하는 데에 O(m + n), O(m), O(n). 셋 다 더하면 O(m + n).
- 나눗셈에 O(1).
- 종합하면 O(m + n)
"""

from math import comb


class Solution:
def uniquePaths(self, m: int, n: int) -> int:
return comb(m + n - 2, n - 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헛 이렇게도 풀 수 있군요.. ㅎㅎ!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 역시 이래서 파이썬 파이썬 하는군요 ㅋㅋ
저도 TS에서 조합을 사용했는데, 부동소수점 문제로 정확한 계산을 못하더라구요. 그런데 파이썬은 이걸 스무스하게 해결해주네요👍