Skip to content

Commit

Permalink
Merge pull request #506 from haklee/main
Browse files Browse the repository at this point in the history
[haklee] week 8
  • Loading branch information
haklee authored Oct 5, 2024
2 parents 8fdb7bc + e55cc8c commit ad69c40
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 0 deletions.
79 changes: 79 additions & 0 deletions clone-graph/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""TC: O(n + e), SC: -
λ…Έλ“œ 개수 n개, 엣지 개수 e개
아이디어:
문제 μ„€λͺ…λΆ€ν„°κ°€ deepcopyλ₯Ό ν•˜λΌλŠ” κ²ƒμ΄λ‹ˆ λ‚΄μž₯ν•¨μˆ˜λ₯Ό μ¨μ„œ deepcopyλ₯Ό ν•΄μ£Όμž.
SC:
- λ‚΄μž₯ν•¨μˆ˜κ°€ ν•„μš”ν•œ 곡간듀을 λ”°λ‘œ 잘 관리해주지 μ•Šμ„κΉŒ? μ•„λ§ˆ λ³€μˆ˜λ₯Ό 읽고 κ·ΈλŒ€λ‘œ λ¦¬ν„΄κ°’μœΌλ‘œ 바꿔쀄듯.
- κ·Έλ ‡λ‹€λ©΄ μΆ”κ°€μ μœΌλ‘œ κ΄€λ¦¬ν•˜λŠ” 곡간은 ν•„μš” μ—†λ‹€.
TC:
- deepcopyλŠ” ν•„μš”ν•œ 정보λ₯Ό κ·ΈλŒ€λ‘œ λ‹€ deepcopy 뜰 뿐이닀. μ•„λ§ˆ node 개수 + edge κ°œμˆ˜μ— λΉ„λ‘€ν•΄μ„œ μ‹œκ°„μ΄
걸릴것 κ°™λ‹€. O(n + e).
"""

"""
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
"""

import copy
from typing import Optional


class Solution:
def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]:
return copy.deepcopy(node)


"""TC: O(e), SC: O(e)
λ…Έλ“œ 개수 n개, 엣지 개수 e개
아이디어:
dfs λŒλ©΄μ„œ λ…Έλ“œλ“€μ„ λ©”λͺ¨ν•΄λ‘μž. neighbors에 νŠΉμ • λ…Έλ“œλ₯Ό μΆ”κ°€ν•΄μ•Ό ν• λ•Œ λ©”λͺ¨μ— 있으면 λ°”λ‘œ κ°€μ Έλ‹€
μ“°κ³ , μ—†μœΌλ©΄ μƒˆλ‘œ λ§Œλ“€μ–΄μ„œ λ©”λͺ¨μ— λ…Έλ“œλ₯Ό μΆ”κ°€ν•œλ‹€.
SC:
- λ…Έλ“œ 총 nκ°œκ°€ memo에 μ˜¬λΌκ°„λ‹€. O(n).
- 각 λ…Έλ“œλ§ˆλ‹€ neighborκ°€ μžˆλ‹€. 각 edgeλ§ˆλ‹€ neighbor λ¦¬μŠ€νŠΈλ“€μ˜ 총 μ•„μ΄ν…œ κ°œμˆ˜μ— 2κ°œμ”© κΈ°μ—¬ν•œλ‹€. O(e).
- λ”ν•˜λ©΄ O(n + e). 즉, λ‘˜ 쀑 더 큰 값이 κ³΅κ°„λ³΅μž‘λ„λ₯Ό μ§€λ°°ν•œλ‹€.
...κ³  μƒκ°ν•˜λŠ” 것이 일차적인 뢄석인데, μ—¬κΈ°μ„œ 더 λ‚˜μ•„κ°ˆ 수 μžˆλ‹€.
- 주어진 쑰건에 λ”°λ₯΄λ©΄ μš°λ¦¬μ—κ²Œ 주어진 κ·Έλž˜ν”„λŠ” connected graphλ‹€. 즉, 엣지 κ°œμˆ˜κ°€ n-1개 이상이닀.
- 즉, O(n) < O(e)κ°€ 무쑰건 μ„±λ¦½ν•˜λ―€λ‘œ, O(e) < O(n + e) < O(e + e) = O(e). 즉, O(e).
TC:
- SC와 λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ 뢄석 κ°€λŠ₯. O(e).
"""

"""
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
"""

from typing import Optional


class Solution:
def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]:
if node is None:
return node

memo = {}

def dfs(node):
if node not in memo:
new_node = Node(node.val, [])
memo[node] = new_node
new_node.neighbors = [dfs(i) for i in node.neighbors]
return memo[node]

return dfs(node)
64 changes: 64 additions & 0 deletions longest-common-subsequence/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""TC: O(m * n), SC: O(m * n)
주어진 λ¬Έμžμ—΄μ˜ 길이λ₯Ό 각각 m, n이라고 ν•˜μž.
아이디어:
- 두 λ¬Έμžμ—΄μ΄ μ£Όμ–΄μ‘ŒλŠ”λ° 끝이 같은 문자라고 ν•˜μž. 이 경우 lcs의 κΈΈμ΄λŠ” 각각의 λ¬Έμžμ—΄μ—μ„œ
끝 문자λ₯Ό μ œκ±°ν•œ λ¬Έμžμ—΄λ‘œ lcs의 길이λ₯Ό κ΅¬ν•œ 값에 1을 λ”ν•œ 값이닀.
- e.g.) abcz, bcdefz의 lcs 길이λ₯Ό `x`라고 ν•œλ‹€λ©΄,
abc/z, bcdef/zμ—μ„œ 끝의 zκ°€ 같은 λ¬Έμžλ‹ˆκΉŒ 이게 lcs에 λ“€μ–΄κ°„λ‹€ μΉ  수 μžˆμœΌλ―€λ‘œ,
abc, bcdef의 lcs κΈΈμ΄λŠ” `x - 1`이 λœλ‹€.
- 두 λ¬Έμžμ—΄μ˜ 끝 λ¬Έμžκ°€ λ‹€λ₯Ό 경우, 첫 번째 λ¬Έμžμ—΄μ˜ 끝 문자λ₯Ό μ œκ±°ν•˜κ³  κ΅¬ν•œ lcs의 κΈΈμ΄λ‚˜
두 번째 λ¬Έμžμ—΄μ˜ 끝 문자λ₯Ό μ œκ³ ν•˜κ³  κ΅¬ν•œ lcs의 길이 λ‘˜ 쀑 큰 값이 μ›λž˜ λ¬Έμžμ—΄λ‘œ κ΅¬ν•œ lcs
의 길이닀.
- e.g.) abcz, bcdefy의 lcs 길이λ₯Ό `x`라고 ν•œλ‹€λ©΄,
abc, bcdefy의 lcs 길이와
abcz, bcdef의 lcs 길이
λ‘˜ 쀑 더 큰 값을 μ·¨ν•˜λ©΄ λœλ‹€.
- LCSλŠ” 유λͺ…ν•œ μ•Œκ³ λ¦¬μ¦˜μ΄λ―€λ‘œ μœ„μ˜ μ„€λͺ…을 μ‹œκ°μ μœΌλ‘œ 잘 ν‘œν˜„ν•œ μ˜ˆμ‹œλ“€μ„ μ˜¨λΌμΈμƒμ—μ„œ μ‰½κ²Œ
찾을 수 μžˆλ‹€.
- μœ„μ˜ 아이디어λ₯Ό μ ν™”μ‹μœΌλ‘œ λ°”κΎΈλ©΄
- 첫 번째 λ¬Έμžμ—΄μ˜ μ•ž iκΈ€μžλ‘œ λ§Œλ“  λ¬Έμžμ—΄κ³Ό 두 번째 λ¬Έμžμ—΄μ˜ μ•ž jκΈ€μžλ‘œ λ§Œλ“  λ¬Έμžμ—΄μ˜
lcs의 길이λ₯Ό lcs(i, j)라고 ν•˜μž.
- 첫 번째 λ¬Έμžμ—΄μ˜ i번째 κΈ€μžμ™€ 두 번째 λ¬Έμžμ—΄μ˜ j번째 κΈ€μžκ°€ 같은 경우 λ‹€μŒμ˜ 식이 성립.
- lcs(i, j) = lcs(i-1, j-1) + 1
- λ‹€λ₯Ό 경우, λ‹€μŒμ˜ 식이 성립.
- lcs(i, j) = max(lcs(i-1, j), lcs(i, j-1))
- μœ„μ˜ 아이디어λ₯Ό memoizeλ₯Ό ν•˜λŠ” dpλ₯Ό 톡해 κ΅¬ν˜„ν•  수 μžˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ μ½”λ“œ μ°Έμ‘°.
SC:
- 첫 번째 λ¬Έμžμ—΄μ˜ μ•ž iκΈ€μžλ‘œ λ§Œλ“  λ¬Έμžμ—΄κ³Ό 두 번째 λ¬Έμžμ—΄μ˜ μ•ž jκΈ€μžλ‘œ λ§Œλ“  λ¬Έμžμ—΄μ˜ lcs의
길이λ₯Ό 관리.
- 그런데 아이디어에 μ œμ‹œλœ 점화식을 보면 i, j값에 λŒ€ν•œ 전체 배열을 μ €μž₯ν•  ν•„μš” 없이 i=kμΌλ•Œ
값을 κ΅¬ν•˜λ € ν•œλ‹€λ©΄ i=k-1μΌλ•Œ κ΅¬ν•œ lcsκ°’λ§Œ μ•Œκ³  있으면 μΆ©λΆ„ν•˜λ‹€.
- 즉, 배열은 ν˜„μž¬ κ΅¬ν•˜κ³ μž ν•˜λŠ” i값에 λŒ€ν•œ j개의 μ•„μ΄ν…œκ³Ό 직전에 κ΅¬ν•œ j개의 μ•„μ΄ν…œλ§Œ μ €μž₯ν•˜λ©΄
μΆ©λΆ„ν•˜λ‹€. 즉, text2의 길이인 O(n)이라고 λ³Ό 수 μžˆλ‹€.
- 그런데 λ§Œμ•½ text2의 길이가 text1보닀 κΈΈλ©΄ 이 λ‘˜μ„ λ°”κΏ”μΉ˜κΈ°ν•΄μ„œ μœ„μ˜ κ³΅κ°„λ³΅μž‘λ„λ₯Ό O(m)이라고
봐도 아이디어 μžμ²΄λŠ” λ˜‘κ°™μ΄ μž‘λ™ν•˜μ§€ μ•ŠλŠ”κ°€?
- 즉, O(min(m, n))
TC:
- dp 배열을 μ±„μš°λŠ” 데에 λ§ˆμ§€λ§‰ λ¬Έμžκ°€ 같을 경우 λ‹¨μˆœ λ§μ…ˆ, λ‹€λ₯Ό 경우 두 κ°’ 비ꡐ. λ‘˜ λ‹€ O(1).
- λ°°μ—΄ μ±„μš°λŠ” 것을 m * n회 λ°˜λ³΅ν•˜λ―€λ‘œ 총 O(m * n).
"""


class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
if len(text2) > len(text1):
# 이 μ΅œμ ν™”κΉŒμ§€ ν•΄μ£Όλ©΄ μ‚¬μš©ν•˜λŠ” λ©”λͺ¨λ¦¬ 크기가 많이 쀄어듀 수 μžˆλ‹€.
text1, text2 = text2, text1

dp = [[0 for _ in range(len(text2) + 1)] for _ in range(2)]

for i in range(1, len(text1) + 1):
i_prev = (i + 1) % 2
i_cur = i % 2
for j in range(1, len(text2) + 1):
dp[i_cur][j] = (
dp[i_prev][j - 1] + 1
if text1[i - 1] == text2[j - 1]
else max(dp[i_prev][j], dp[i_cur][j - 1])
)

return dp[i_cur][-1]
36 changes: 36 additions & 0 deletions longest-repeating-character-replacement/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""TC: O(n), SC: O(1)
n은 주어진 λ¬Έμžμ—΄μ˜ 길이
아이디어:
- 투 포인터λ₯Ό μ¨μ„œ λ¬Έμžμ—΄μ˜ μ‹œμž‘, 끝을 κ΄€λ¦¬ν•˜λ©΄μ„œ λΆ€λΆ„ λ¬Έμžμ—΄μ„ λ§Œλ“ λ‹€.
- λΆ€λΆ„ λ¬Έμžμ—΄μ— λ“€μ–΄μžˆλŠ” 문자 쀑 κ°€μž₯ λ§Žμ€ λ¬Έμžμ™€ k의 합이 λ¬Έμžμ—΄μ˜ 길이 보닀 크면 쑰건 만쑱.
- λΆ€λΆ„ λ¬Έμžμ—΄μ— λ“€μ–΄μžˆλŠ” 문자 개수λ₯Ό dictλ₯Ό μ¨μ„œ κ΄€λ¦¬ν•˜μž.
SC:
- λΆ€λΆ„ λ¬Έμžμ—΄μ— λ“€μ–΄μžˆλŠ” 문자 개수λ₯Ό κ΄€λ¦¬ν•˜λŠ” dictμ—μ„œ O(1).
- λΆ€λΆ„ λ¬Έμžμ—΄μ˜ μ‹œμž‘, 끝 인덱슀 관리 O(1).
- μ’…ν•©ν•˜λ©΄ O(1).
TC:
- λΆ€λΆ„ λ¬Έμžμ—΄μ˜ 끝 인덱슀λ₯Ό ν•˜λ‚˜ 늘릴 λ•Œλ§ˆλ‹€ λ°˜ν™˜ν•  κ°’ μ—…λ°μ΄νŠΈ. O(1)을 n번 μ‹œν–‰ν•˜λ―€λ‘œ O(n).
- μ‹œμž‘, 끝 인덱슀 μˆ˜μ •ν•  λ•Œλ§ˆλ‹€ λΆ€λΆ„ λ¬Έμžμ—΄μ— λ“€μ–΄μžˆλŠ” 문자 개수 μ—…λ°μ΄νŠΈ. μ‹œμž‘, 끝 μΈλ±μŠ€λŠ”
많이 μˆ˜μ •ν•΄λ΄μ•Ό ν•©μ³μ„œ 2*n번. 즉, O(1)을 2*n번 μ‹œν–‰ν•˜λ―€λ‘œ O(n).
- μ‹œμž‘, 끝 μΈλ±μŠ€μ— 1을 λ”ν•˜λŠ” μ‹œν–‰. O(1)을 2*n번 μ‹œν–‰ν•˜λ―€λ‘œ O(n).
- μ’…ν•©ν•˜λ©΄ O(n).
"""


class Solution:
def characterReplacement(self, string: str, k: int) -> int:
char_cnt = {c: 0 for c in set(string)}
s = e = 0
sol = -1
while e < len(string):
char_cnt[string[e]] += 1
while e - s + 1 > max(char_cnt.values()) + k:
char_cnt[string[s]] -= 1
s += 1
sol = max(e - s + 1, sol)
e += 1
return sol
65 changes: 65 additions & 0 deletions merge-two-sorted-lists/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""TC: O(n), SC: -
n은 주어진 두 리슀트의 길이 쀑 큰 κ°’
아이디어:
- 주어진 쑰건에 μ˜ν•΄ 두 λ¦¬μŠ€νŠΈμ— λ“€μ–΄μžˆλŠ” 값듀은 non-decreasingμ΄λ―€λ‘œ, μƒˆλ‘œμš΄ 리슀트λ₯Ό λ§Œλ“€κ³ 
두 리슀트의 μ•žμ— μžˆλŠ” κ°’ 쀑 μž‘μ€ 값을 ν•˜λ‚˜μ”© λ½‘μ•„μ„œ 더해주면 λœλ‹€.
- 빈 λ¦¬μŠ€νŠΈκ°€ μ£Όμ–΄μ§ˆ 수 μžˆλŠ” κ²ƒλ§Œ μœ μ˜ν•˜μž.
SC:
- νŠΉλ³„νžˆ κ΄€λ¦¬ν•˜λŠ” 값이 μ—†λ‹€.
TC:
- λͺ¨λ“  λ…Έλ“œμ— ν•œ λ²ˆμ”© μ ‘κ·Όν•΄μ„œ 리턴할 값에 이어쀀닀. μ΄μ–΄μ£ΌλŠ” μ‹œν–‰λ§ˆλ‹€ O(1).
- 리턴할 값에 μƒˆ λ…Έλ“œλ₯Ό μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ κ°’ 비ꡐλ₯Ό ν•œ λ²ˆμ”© ν•œλ‹€. O(1).
- n이 두 리슀트 길이 쀑 큰 κ°’μ΄λ―€λ‘œ μ΄μ–΄μ£ΌλŠ” μ‹œν–‰μ€ xλŠ” n <= x <= 2*n 만쑱.
- 즉, 총 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 mergeTwoLists(
self, list1: Optional[ListNode], list2: Optional[ListNode]
) -> Optional[ListNode]:
# 1. init head
# - 두 리슀트λ₯Ό 보고 ν˜Ήμ‹œ ν•˜λ‚˜λΌλ„ λΉ„μ–΄μžˆμœΌλ©΄ λ‹€λ₯Έ 리슀트λ₯Ό λ¦¬ν„΄ν•œλ‹€.
# - λ‘˜ λ‹€ λΉ„μ–΄μžˆμ§€ μ•Šμ„ 경우 첫 μ•„μ΄ν…œμ„ 보고 λ‘˜ 쀑 μž‘μ€ 값을 결과물의 첫 μ•„μ΄ν…œμœΌλ‘œ 씀.
if list1 is None:
return list2
if list2 is None:
return list1
# μ—¬κΈ° λ„λ‹¬ν–ˆμœΌλ©΄ λ‘˜ λ‹€ μ΅œμ†Œν•œ ν•œ μ•„μ΄ν…œμ”©μ€ 쑴재.
sol = None
if list1.val < list2.val:
sol = ListNode(list1.val)
list1 = list1.next
else:
sol = ListNode(list2.val)
list2 = list2.next

sol_head = sol

# 2. add item
# - μ•žμ˜ 과정을 λΉ„μŠ·ν•˜κ²Œ λ°˜λ³΅ν•œλ‹€.
while True:
# μ–Έμ  κ°€ λ‘˜ 쀑 ν•œ λ¦¬μŠ€νŠΈλŠ” λΉ„κ²Œ λ˜λ―€λ‘œ λ¬΄ν•œ 루프λ₯Ό λŒμ§€ μ•ŠλŠ”λ‹€.
if list1 is None:
sol_head.next = list2
return sol
if list2 is None:
sol_head.next = list1
return sol

if list1.val < list2.val:
sol_head.next = ListNode(list1.val)
list1 = list1.next
else:
sol_head.next = ListNode(list2.val)
list2 = list2.next

sol_head = sol_head.next
133 changes: 133 additions & 0 deletions sum-of-two-integers/haklee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
"""TC: O(1), SC: O(n^2)
-n <= a, b <= n κ°€μ •.
λ¬Έμ œμ—μ„œλŠ” n이 1000으둜 μ£Όμ–΄μ Έμžˆλ‹€κ³  λ³Ό 수 μžˆλ‹€.
아이디어:
λ§μ…ˆμ„ λͺ» μ“°κ²Œ ν•œλ‹€λ©΄ μ „μ²˜λ¦¬λ₯Ό 톡해 λͺ¨λ“  a, b 쑰합에 λŒ€ν•œ λ§μ…ˆ 값을 λ§Œλ“€μ–΄λ†“κ³  a, b의 값에 λ”°λΌμ„œ
ν•„μš”ν•œ 값을 좜λ ₯ν•˜λ„λ‘ ν•˜μž. pythonμ—μ„œλŠ” 음수둜 된 인덱슀λ₯Ό μ§€μ›ν•˜λ―€λ‘œ 이λ₯Ό ν™œμš©ν•˜μž.
- μ•„λž˜μ˜ μ½”λ“œλ₯Ό ν†΅ν•΄μ„œ μ „μ²˜λ¦¬λœ 값을 μ€€λΉ„ν•œλ‹€. 이 μ½”λ“œλŠ” leetcodeμ—μ„œ μ‹€ν–‰λ˜μ§€ μ•ŠμœΌλ―€λ‘œ λ”ν•˜κΈ°λ₯Ό
써도 상관 μ—†λ‹€.
```py
n = 3
with open("foo.txt", "w") as f:
a = [
[
(i if i <= n else i - 2 * n - 1) + (j if j <= n else j - 2 * n - 1)
for j in range(0, 2 * n + 1)
]
for i in range(0, 2 * n + 1)
]
f.write(str(a))
```
SC:
- O(n^2). μ •ν™•νžˆλŠ”, (2*n+1)^2 개의 μ •μˆ˜λ₯Ό 배열에 μ €μž₯ν•œλ‹€.
TC:
- 인덱슀λ₯Ό 톡해 λ°”λ‘œ μ ‘κ·Ό. O(1).
"""


class Solution:
# n = 3μΌλ•Œ μ˜ˆμ‹œ.
def getSum(self, a: int, b: int) -> int:
x = [
[0, 1, 2, 3, -3, -2, -1],
[1, 2, 3, 4, -2, -1, 0],
[2, 3, 4, 5, -1, 0, 1],
[3, 4, 5, 6, 0, 1, 2],
[-3, -2, -1, 0, -6, -5, -4],
[-2, -1, 0, 1, -5, -4, -3],
[-1, 0, 1, 2, -4, -3, -2],
]
return x[a][b]


# 단, n = 1000μΌλ•Œ 이런 μ‹μœΌλ‘œ μ½”λ“œλ₯Ό 짜렀고 ν•˜λ©΄
# `For performance reasons, the number of characters per line is limited to 10,000.`
# ν•˜λŠ” 문ꡬ와 ν•¨κ»˜ 리슀트λ₯Ό 볡뢙할 μˆ˜κ°€ μ—†λ‹€...


"""TC: O(n), SC: O(n)
-n <= a, b <= n κ°€μ •.
λ¬Έμ œμ—μ„œλŠ” n이 1000으둜 μ£Όμ–΄μ Έμžˆλ‹€κ³  λ³Ό 수 μžˆλ‹€.
아이디어:
μ „μ²˜λ¦¬ ν•œ 것을 κ°€μ Έμ˜€λŠ” 방법은 λͺ» μ“°κ²Œ λ˜μ—ˆμ§€λ§Œ, 인덱슀λ₯Ό ν†΅ν•œ 접근은 아직 κ·ΈλŒ€λ‘œ μ“°κ³  μ‹Άλ‹€.
- 문제의 쑰건을 λ°”κΏ”μ„œ 0 <= a, b <= n라고 ν•΄λ³΄μž. 그리고 n이 3이라고 ν•΄λ³΄μž.
- aκ°€ 0으둜 κ³ μ •λ˜μ–΄ μžˆλ‹€λ©΄, λ‹€μŒκ³Ό 같은 배열이 μ£Όμ–΄μ‘Œμ„λ•Œ a+b의 값을 인덱슀둜 μ ‘κ·Όν•  수 μžˆλ‹€.
- v = [0, 1, 2, 3] μΌλ•Œ a + b 값은 v[b]
- aκ°€ 1둜 κ³ μ •λ˜μ–΄ μžˆλ‹€λ©΄,
- v = [1, 2, 3, 4] μΌλ•Œ a + b 값은 v[b]
- aκ°€ 2둜 κ³ μ •λ˜μ–΄ μžˆλ‹€λ©΄,
- v = [2, 3, 4, 5] μΌλ•Œ a + b 값은 v[b]
- aκ°€ 3으둜 κ³ μ •λ˜μ–΄ μžˆλ‹€λ©΄,
- v = [3, 4, 5, 6] μΌλ•Œ a + b 값은 v[b]
- μœ„μ˜ 배열을 보면 κ²ΉμΉ˜λŠ” μˆ«μžλ“€μ΄ λ§Žλ‹€. κ·Έλ ‡λ‹€λ©΄ 0~6κΉŒμ§€ μˆ«μžλ“€μ΄ λ“€μ–΄μžˆλŠ” 배열을 slicingν•΄μ„œ
μ“°λ©΄ λ˜μ§€ μ•Šμ„κΉŒ?
- aκ°€ 0μΌλ•Œ v = [0, 1, 2, 3, 4, 5, 6] 쀑
[0, 1, 2, 3] μ‚¬μš©.
즉, v[0:4] μ‚¬μš©.
- aκ°€ 1μΌλ•Œ v = [0, 1, 2, 3, 4, 5, 6] 쀑
[1, 2, 3, 4] μ‚¬μš©.
즉, v[1:5] μ‚¬μš©.
...
- μΌλ°˜ν™”ν•˜λ©΄, v[a:a+n+1] μ‚¬μš©. μ΄λ•Œ a+b 값은 v = list(range(0, 2 * n + 1))μΌλ•Œ v[a:a+n+1][b].
- 그런데 v[a:a+n+1][b]λ₯Ό 보면 μŠ¬λΌμ΄μ‹± ν•˜λŠ” λΆ€λΆ„μ—μ„œ + 기호λ₯Ό μ‚¬μš©ν–ˆλ‹€.
- κ·Έλ ‡λ‹€λ©΄ μ €κΈ°μ„œ λ”ν•˜κΈ° 기호λ₯Ό μ‚¬μš©ν•  ν•„μš” 없이 μŠ¬λΌμ΄μ‹±μ˜ μ‹œμž‘ κ°’κ³Ό 끝 값도 미리 리슀트둜 λ§Œλ“€κ³ ,
이 λ¦¬μŠ€νŠΈμ—μ„œ a번째 μ•„μ΄ν…œμ„ κ°€μ Έμ˜€λŠ” 방식을 ν™œμš©ν•΄λ³΄μž.
- s = [0, 1, 2, 3], e = [4, 5, 6, 7]μΌλ•Œ, v[a:a+n+1][b] = v[s[a]:e[a]][b]κ°€ λœλ‹€.
- μΌλ°˜ν™”ν•˜λ©΄, s = list(range(0, n)), e = list(range(n+1, 2*n+1))이면 λœλ‹€.
- eλ₯Ό λ§Œλ“€λ©΄μ„œ λ”ν•˜κΈ°λ₯Ό μ“΄ κ²ƒμ²˜λŸΌ λ³΄μ΄μ§€λ§Œ, μ‹€μ œλ‘œλŠ” n이 주어진 μƒμˆ˜μ΄λ―€λ‘œ 값을 κ³„μ‚°ν•΄μ„œ λ„£μœΌλ©΄ λœλ‹€.
- 예λ₯Ό λ“€μ–΄, n=3μΌλ•Œ e = list(range(4, 7))이닀.
큰 μ•„μ΄λ””μ–΄λŠ” μœ„μ˜ λ°©μ‹μœΌλ‘œ μ„€λͺ…이 끝났닀. 이제 λ¬Έμ œλŠ” 0 <= a, b <= n이 μ•„λ‹ˆλΌ -n <= a, b <= n λ²”μœ„μ—μ„œλ„
μœ„μ˜ 방식이 μž‘λ™ν•˜λ„λ‘ ν•˜λŠ” 것인데, λ¨Όμ € a값은 μ–‘μˆ˜ λ²”μœ„μ— 두고 bκ°’λ§Œ 음수둜 ν™•μž₯ν•œ μƒνƒœμ—μ„œ vλ₯Ό ꡬ해보고,
κ·Έ λ‹€μŒ a도 μŒμˆ˜κΉŒμ§€ ν™•μž₯ν•˜λŠ” μ‹μœΌλ‘œ μ ‘κ·Όν•˜λ©΄ λœλ‹€. μžμ„Έν•œ μ„€λͺ…은 μƒλž΅ν•˜κ³ , λ‘˜ λ‹€ 음수 λ²”μœ„κΉŒμ§€ ν™•μž₯ν•œ λ’€
μ‹€μ œλ‘œ μž‘λ™ν•˜λŠ” 결과물을 μ„€λͺ…ν•˜λŠ” κ²ƒμœΌλ‘œ λŒ€μ‹ ν•˜κ² λ‹€.
- n은 3이라고 κ°€μ •ν•˜κ² λ‹€.
- v = [0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1]
- list(range(0, n+1))에 list(range(-n, 0))을 이어뢙인 것을 두 번 λ°˜λ³΅ν–ˆλ‹€.
- 두 번 λ°˜λ³΅ν•œ μ΄μœ λŠ” a값이 μŒμˆ˜κ°€ 된 상황에 λŒ€μ‘ν•˜κΈ° μœ„ν•¨μ΄λ‹€. μ•„λž˜μ˜ μ„€λͺ…을 μ΄μ–΄μ„œ 보도둝 ν•˜μž.
- s = list(range(0, 4 * n + 1)) = list(range(0, 13))이닀.
- μ΄λ ‡κ²Œ ν•˜λ©΄ aκ°€ μŒμˆ˜κ°€ λ˜μ—ˆμ„λ•Œλ„ slicing을 μ‹œμž‘ν•  μΈλ±μŠ€λŠ” μ–‘μˆ˜λ‘œ μœ μ§€ν•  수 μžˆλ‹€.
- bλ₯Ό 0으둜 κ³ μ •ν•˜λ©΄ slicing을 μ‹œμž‘ν•˜λŠ” μΈλ±μŠ€μ— μžˆλŠ” μ•„μ΄ν…œμ΄ a+b의 값이 λ˜μ–΄μ•Ό ν•œλ‹€.
- 이λ₯Ό μœ„μ˜ v와 같이 μƒκ°ν•˜λ©΄ v의 μ•ž 13개 μ•„μ΄ν…œμ„ μ·¨ν•œ [0, 1, 2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1]
배열이 μžˆμ„λ•Œ aκ°€ μ·¨ν•  수 μžˆλŠ” κ°’μ˜ λ²”μœ„λŠ” -3~3μ΄λ―€λ‘œ [0, 1, 2, 3, ..., -3, -2, -1] 쀑 ν•˜λ‚˜λΆ€ν„°
slicing이 μ‹œμž‘λœλ‹€κ³  보면 λœλ‹€.
- κ·ΈλŸ¬λ‹ˆκΉŒ μ‰½κ²Œ λ§ν•΄μ„œ a의 λ²”μœ„λ‘œ 인해 slicing이 μ•„μ΄ν…œ 4λΆ€ν„° μ‹œμž‘ν•΄μ„œ [4, 5, 6, -6, ...] ν•˜λŠ” 일이
μΌμ–΄λ‚˜μ§€λŠ” μ•ŠλŠ”λ‹€λŠ” 뜻.
- slicingν•œ λ°°μ—΄μ˜ ν¬κΈ°λŠ” 4*n+1이어야 ν•œλ‹€. eλŠ” s의 각 μ•„μ΄ν…œμ— 4*n+1을 λ”ν•œ 값이면 λœλ‹€.
- 4*n+1은 관찰을 톡해 얻을 수 μžˆλŠ” 값이닀.a, b의 ν•©μ˜ μ΅œμ†Œκ°€ -2*n, μ΅œλŒ€κ°€ 2*nμ΄μ–΄μ„œ κ·Έ 사이에 μžˆλŠ”
μˆ«μžλ“€μ΄ 총 4*n+1개 μžˆλ‹€λŠ” κ²ƒμ—μ„œ λΉ„λ‘―λœ μˆ«μžλ‹€.
- 끝에 μ˜ˆμ‹œλ₯Ό 보면 이해가 μ’€ 더 νŽΈν•˜λ‹€.
- μ •λ¦¬ν•˜λ©΄, e = list(range(4*n+1, 8*n+2)) = list(range(13, 26))이닀.
- a+b 값은 v[s[a] : e[a]][b] 둜 ꡬ할 수 μžˆλ‹€.
- 예λ₯Ό λ“€μ–΄, a=2, b=-3이라고 ν• λ•Œ
- v[s[a] : e[a]] = v[2:15] = [2, 3, 4, 5, 6, -6, -5, -4, -3, -2, -1, 0, 1]λ‹€.
- bκ°€ -3μ΄λ―€λ‘œ μœ„μ˜ slicing된 λ°°μ—΄μ—μ„œ λ’€μ—μ„œ μ„Έ 번째 μ•„μ΄ν…œμ„ 찾으면 λœλ‹€. 즉, -1이닀.
- 잘 κ΄€μ°°ν•˜λ©΄ λ§μ…ˆμ˜ κ²°κ³Όκ°€ 될 수 μžˆλŠ” 값은 [2, 3, 4, 5, ..., -1, 0, 1] 밖에 μ—†λ‹€. 사이에 μžˆλŠ” μˆ«μžλŠ”
b의 λ²”μœ„κ°€ μ œν•œλ˜μ–΄ μžˆμ–΄μ„œ μ ‘κ·Ό λΆˆκ°€λŠ₯ν•œ, 즉, ν•„μš” μ—†λŠ” μˆ«μžλ“€μ΄λΌκ³  보면 λœλ‹€.
SC:
- μ½”λ“œ μ°Έμ‘°. O(n).
TC:
- 인덱슀λ₯Ό 톡해 λ°”λ‘œ μ ‘κ·Ό. O(1).
"""


class Solution:
def getSum(self, a: int, b: int) -> int:
x = list(range(0, 2001))
x.extend(list(range(-2000, 0)))
v = x * 2 # SC: O(n)
s = list(range(0, 4001)) # SC: O(n)
e = list(range(4001, 8002)) # SC: O(n)
return v[s[a] : e[a]][b]

0 comments on commit ad69c40

Please sign in to comment.