ํŒŒ์ด์ฌ PS 1๋‹จ๊ณ„: ๊ธฐ์ดˆ ๋ฌธ๋ฒ• ์™„์ „์ •๋ณต

๐Ÿ“ฅ 1. ์ž…์ถœ๋ ฅ ์ฒ˜๋ฆฌ

๊ธฐ๋ณธ ์ž…๋ ฅ

# ํ•œ ์ค„ ์ž…๋ ฅ
n = int(input())
s = input()
a, b = map(int, input().split())

# ์—ฌ๋Ÿฌ ์ค„ ์ž…๋ ฅ
arr = []
for _ in range(n):
    arr.append(int(input()))

# ๋ฆฌ์ŠคํŠธ ํ•œ๋ฒˆ์— ์ž…๋ ฅ
numbers = list(map(int, input().split()))

๋น ๋ฅธ ์ž…๋ ฅ (sys.stdin)

import sys
input = sys.stdin.readline

# ์ฃผ์˜: readline()์€ ๊ฐœํ–‰๋ฌธ์ž๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ
n = int(input())  # ์ˆซ์ž๋Š” ์ž๋™์œผ๋กœ ๊ฐœํ–‰๋ฌธ์ž ์ œ๊ฑฐ
s = input().strip()  # ๋ฌธ์ž์—ด์€ strip() ํ•„์š”

์ถœ๋ ฅ ์ตœ์ ํ™”

# ๊ธฐ๋ณธ ์ถœ๋ ฅ
print(result)
print(a, b, c)  # ๊ณต๋ฐฑ์œผ๋กœ ๊ตฌ๋ถ„
print(a, b, c, sep=', ')  # ๊ตฌ๋ถ„์ž ์ง€์ •

# ๋น ๋ฅธ ์ถœ๋ ฅ (๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ)
import sys
print = sys.stdout.write
# ์‚ฌ์šฉ ์‹œ ๊ฐœํ–‰๋ฌธ์ž ์ง์ ‘ ์ถ”๊ฐ€ ํ•„์š”: print(str(result) + '\n')

# ์—ฌ๋Ÿฌ ์ค„ ์ถœ๋ ฅ
results = []
for i in range(n):
    results.append(str(i))
print('\n'.join(results))

๐Ÿšจ ์ž…์ถœ๋ ฅ ์ฃผ์š” ํ•จ์ •

  • input().split()์˜ ๊ฒฐ๊ณผ๋Š” ๋ฌธ์ž์—ด ๋ฆฌ์ŠคํŠธ
  • sys.stdin.readline()์€ ๊ฐœํ–‰๋ฌธ์ž ํฌํ•จ
  • ๋Œ€๋Ÿ‰ ์ถœ๋ ฅ ์‹œ print() ์—ฌ๋Ÿฌ ๋ฒˆ๋ณด๋‹ค ํ•œ ๋ฒˆ์— ์ถœ๋ ฅ์ด ๋น ๋ฆ„

๐Ÿ”ค 2. ๋ฌธ์ž์—ด(String) ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ ์กฐ์ž‘

s = "Hello World"

# ๊ธธ์ด์™€ ์ธ๋ฑ์‹ฑ
len(s)  # 11
s[0]    # 'H'
s[-1]   # 'd'
s[1:5]  # 'ello'

# ๋Œ€์†Œ๋ฌธ์ž ๋ณ€ํ™˜
s.upper()      # 'HELLO WORLD'
s.lower()      # 'hello world'
s.capitalize() # 'Hello world'
s.title()      # 'Hello World'

# ๊ณต๋ฐฑ ์ฒ˜๋ฆฌ
s.strip()      # ์–‘์ชฝ ๊ณต๋ฐฑ ์ œ๊ฑฐ
s.lstrip()     # ์™ผ์ชฝ ๊ณต๋ฐฑ ์ œ๊ฑฐ
s.rstrip()     # ์˜ค๋ฅธ์ชฝ ๊ณต๋ฐฑ ์ œ๊ฑฐ

๊ฒ€์ƒ‰๊ณผ ๋ถ„ํ• 

s = "hello world hello"

# ๊ฒ€์ƒ‰
s.find('world')     # 6 (์ฒซ ๋ฒˆ์งธ ์ธ๋ฑ์Šค)
s.find('xyz')       # -1 (์—†์Œ)
s.index('world')    # 6 (์—†์œผ๋ฉด ValueError)
s.count('hello')    # 2

# ๋ถ„ํ• ๊ณผ ๊ฒฐํ•ฉ
s.split()           # ['hello', 'world', 'hello']
s.split('l')        # ['he', '', 'o wor', 'd he', '', 'o']
' '.join(['a', 'b', 'c'])  # 'a b c'

# ์น˜ํ™˜
s.replace('hello', 'hi')  # 'hi world hi'
s.replace('l', 'L', 2)    # 'heLLo world hello' (์ตœ๋Œ€ 2๊ฐœ๋งŒ)

ํŒ๋ณ„ ๋ฉ”์„œ๋“œ

# ๋ฌธ์ž ์ข…๋ฅ˜ ํŒ๋ณ„
'123'.isdigit()      # True
'abc'.isalpha()      # True
'abc123'.isalnum()   # True
'   '.isspace()      # True

# ํŒจํ„ด ํŒ๋ณ„
'hello'.startswith('he')  # True
'world'.endswith('ld')    # True

๐Ÿšจ ๋ฌธ์ž์—ด ์ฃผ์š” ํ•จ์ •

  • ๋ฌธ์ž์—ด์€ ๋ถˆ๋ณ€(immutable) โ†’ ์ˆ˜์ • ์‹œ ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ
  • split()๊ณผ split(' ')๋Š” ๋‹ค๋ฆ„ (์—ฐ์† ๊ณต๋ฐฑ ์ฒ˜๋ฆฌ ๋ฐฉ์‹)
  • ๋Œ€๋Ÿ‰ ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ ์‹œ ''.join(list)๊ฐ€ + ์—ฐ์‚ฐ๋ณด๋‹ค ๋น ๋ฆ„

๐Ÿ“‹ 3. ๋ฆฌ์ŠคํŠธ(List) ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ ์ƒ์„ฑ๊ณผ ์กฐ์ž‘

# ์ƒ์„ฑ
arr = [1, 2, 3, 4, 5]
arr2 = [0] * n  # ํฌ๊ธฐ n์ธ 0์œผ๋กœ ์ดˆ๊ธฐํ™”๋œ ๋ฆฌ์ŠคํŠธ
matrix = [[0] * m for _ in range(n)]  # 2์ฐจ์› ๋ฆฌ์ŠคํŠธ

# ์ถ”๊ฐ€์™€ ์‚ญ์ œ
arr.append(6)        # ๋์— ์ถ”๊ฐ€: [1,2,3,4,5,6]
arr.insert(0, 0)     # ์ธ๋ฑ์Šค 0์— ์‚ฝ์ž…: [0,1,2,3,4,5,6]
arr.extend([7, 8])   # ๋ฆฌ์ŠคํŠธ ํ™•์žฅ: [0,1,2,3,4,5,6,7,8]

arr.pop()            # ๋งˆ์ง€๋ง‰ ์š”์†Œ ์ œ๊ฑฐ ํ›„ ๋ฐ˜ํ™˜: 8
arr.pop(0)           # ์ธ๋ฑ์Šค 0 ์š”์†Œ ์ œ๊ฑฐ ํ›„ ๋ฐ˜ํ™˜: 0
arr.remove(3)        # ๊ฐ’ 3์ธ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ์ œ๊ฑฐ

์ •๋ ฌ๊ณผ ๊ฒ€์ƒ‰

arr = [3, 1, 4, 1, 5]

# ์ •๋ ฌ
arr.sort()                    # ์›๋ณธ ์ˆ˜์ •: [1,1,3,4,5]
sorted_arr = sorted(arr)      # ์ƒˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
arr.sort(reverse=True)        # ๋‚ด๋ฆผ์ฐจ์ˆœ: [5,4,3,1,1]
arr.sort(key=len)            # ๋ฌธ์ž์—ด ๊ธธ์ด๋กœ ์ •๋ ฌ

# ๊ฒ€์ƒ‰
arr.index(4)         # 4์˜ ์ธ๋ฑ์Šค: 2
arr.count(1)         # 1์˜ ๊ฐœ์ˆ˜: 2
4 in arr            # True

์Šฌ๋ผ์ด์‹ฑ๊ณผ ๋ณต์‚ฌ

arr = [1, 2, 3, 4, 5]

# ์Šฌ๋ผ์ด์‹ฑ
arr[1:4]        # [2, 3, 4]
arr[:3]         # [1, 2, 3]
arr[2:]         # [3, 4, 5]
arr[::2]        # [1, 3, 5] (2์นธ์”ฉ)
arr[::-1]       # [5, 4, 3, 2, 1] (๋’ค์ง‘๊ธฐ)

# ๋ณต์‚ฌ
shallow = arr[:]           # ์–•์€ ๋ณต์‚ฌ
deep = [x for x in arr]    # ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜์œผ๋กœ ๋ณต์‚ฌ
import copy
deep_copy = copy.deepcopy(arr)  # ๊นŠ์€ ๋ณต์‚ฌ

๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜

# ๊ธฐ๋ณธ ํ˜•ํƒœ
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]

# ์ค‘์ฒฉ ๋ฃจํ”„
pairs = [(x, y) for x in range(3) for y in range(3)]

# ์กฐ๊ฑด๋ถ€ ํ‘œํ˜„์‹
result = [x if x > 0 else 0 for x in [-1, 2, -3, 4]]

๐Ÿšจ ๋ฆฌ์ŠคํŠธ ์ฃผ์š” ํ•จ์ •

  • [[0] * m] * n์€ ๊ฐ™์€ ๋ฆฌ์ŠคํŠธ ๊ฐ์ฒด๋ฅผ n๋ฒˆ ์ฐธ์กฐ (์–•์€ ๋ณต์‚ฌ)
  • sort()๋Š” ์›๋ณธ ์ˆ˜์ •, sorted()๋Š” ์ƒˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
  • ๋ฆฌ์ŠคํŠธ ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ๋Š” O(n) ์‹œ๊ฐ„๋ณต์žก๋„

๐Ÿ“– 4. ๋”•์…”๋„ˆ๋ฆฌ(Dictionary) ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ ์กฐ์ž‘

# ์ƒ์„ฑ
d = {'a': 1, 'b': 2}
d2 = dict(a=1, b=2)
d3 = dict([('a', 1), ('b', 2)])

# ์ ‘๊ทผ๊ณผ ์ˆ˜์ •
d['a']              # 1
d.get('c', 0)       # ํ‚ค 'c'๊ฐ€ ์—†์œผ๋ฉด 0 ๋ฐ˜ํ™˜
d['c'] = 3          # ์ƒˆ ํ‚ค-๊ฐ’ ์ถ”๊ฐ€
d.update({'d': 4, 'e': 5})  # ์—ฌ๋Ÿฌ ํ‚ค-๊ฐ’ ์ถ”๊ฐ€

์กฐํšŒ์™€ ์ˆœํšŒ

d = {'a': 1, 'b': 2, 'c': 3}

# ํ‚ค, ๊ฐ’, ํ•ญ๋ชฉ ์กฐํšŒ
d.keys()           # dict_keys(['a', 'b', 'c'])
d.values()         # dict_values([1, 2, 3])
d.items()          # dict_items([('a', 1), ('b', 2), ('c', 3)])

# ์ˆœํšŒ
for key in d:              # ํ‚ค ์ˆœํšŒ
    print(key, d[key])

for key, value in d.items():  # ํ‚ค-๊ฐ’ ์Œ ์ˆœํšŒ
    print(key, value)

# ์กด์žฌ ํ™•์ธ
'a' in d           # True (ํ‚ค ์กด์žฌ ํ™•์ธ)
1 in d.values()    # True (๊ฐ’ ์กด์žฌ ํ™•์ธ)

๊ณ ๊ธ‰ ํ™œ์šฉ

# defaultdict ํ™œ์šฉ
from collections import defaultdict
dd = defaultdict(int)  # ๊ธฐ๋ณธ๊ฐ’ 0
dd = defaultdict(list) # ๊ธฐ๋ณธ๊ฐ’ ๋นˆ ๋ฆฌ์ŠคํŠธ

# Counter ํ™œ์šฉ
from collections import Counter
counter = Counter([1, 2, 2, 3, 3, 3])
# Counter({3: 3, 2: 2, 1: 1})
counter.most_common(2)  # [(3, 3), (2, 2)]

# ๋”•์…”๋„ˆ๋ฆฌ ์ปดํ”„๋ฆฌํ—จ์…˜
squares = {x: x**2 for x in range(5)}
filtered = {k: v for k, v in d.items() if v > 1}

๐Ÿšจ ๋”•์…”๋„ˆ๋ฆฌ ์ฃผ์š” ํ•จ์ •

  • ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ‚ค ์ ‘๊ทผ ์‹œ KeyError โ†’ get() ์‚ฌ์šฉ ๊ถŒ์žฅ
  • Python 3.7+ ์—์„œ ๋”•์…”๋„ˆ๋ฆฌ๋Š” ์‚ฝ์ž… ์ˆœ์„œ ๋ณด์žฅ
  • ์ˆœํšŒ ์ค‘ ๋”•์…”๋„ˆ๋ฆฌ ํฌ๊ธฐ ๋ณ€๊ฒฝ ์‹œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

๐Ÿ”ข 5. ์ง‘ํ•ฉ(Set) ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ ์กฐ์ž‘

# ์ƒ์„ฑ
s = {1, 2, 3, 4, 5}
s2 = set([1, 2, 2, 3, 3])  # {1, 2, 3} (์ค‘๋ณต ์ œ๊ฑฐ)
empty_set = set()          # ๋นˆ ์ง‘ํ•ฉ ({}๋Š” ๋”•์…”๋„ˆ๋ฆฌ)

# ์ถ”๊ฐ€์™€ ์ œ๊ฑฐ
s.add(6)           # ์š”์†Œ ์ถ”๊ฐ€
s.update([7, 8])   # ์—ฌ๋Ÿฌ ์š”์†Œ ์ถ”๊ฐ€
s.remove(5)        # ์š”์†Œ ์ œ๊ฑฐ (์—†์œผ๋ฉด KeyError)
s.discard(5)       # ์š”์†Œ ์ œ๊ฑฐ (์—†์–ด๋„ ์˜ค๋ฅ˜ ์—†์Œ)
s.pop()            # ์ž„์˜ ์š”์†Œ ์ œ๊ฑฐ ํ›„ ๋ฐ˜ํ™˜
s.clear()          # ๋ชจ๋“  ์š”์†Œ ์ œ๊ฑฐ

์ง‘ํ•ฉ ์—ฐ์‚ฐ

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# ํ•ฉ์ง‘ํ•ฉ
a | b              # {1, 2, 3, 4, 5, 6}
a.union(b)

# ๊ต์ง‘ํ•ฉ
a & b              # {3, 4}
a.intersection(b)

# ์ฐจ์ง‘ํ•ฉ
a - b              # {1, 2}
a.difference(b)

# ๋Œ€์นญ์ฐจ์ง‘ํ•ฉ
a ^ b              # {1, 2, 5, 6}
a.symmetric_difference(b)

# ๋ถ€๋ถ„์ง‘ํ•ฉ ํŒ๋ณ„
{1, 2}.issubset({1, 2, 3})     # True
{1, 2, 3}.issuperset({1, 2})   # True

๐Ÿšจ ์ง‘ํ•ฉ ์ฃผ์š” ํ•จ์ •

  • ๋นˆ ์ง‘ํ•ฉ์€ set(), {}๋Š” ๋นˆ ๋”•์…”๋„ˆ๋ฆฌ
  • ์ง‘ํ•ฉ์€ ์ˆœ์„œ๊ฐ€ ์—†์Œ โ†’ ์ธ๋ฑ์‹ฑ ๋ถˆ๊ฐ€
  • ํ•ด์‹œ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋งŒ ์ €์žฅ ๊ฐ€๋Šฅ (list๋Š” ๋ถˆ๊ฐ€, tuple์€ ๊ฐ€๋Šฅ)

๐Ÿ”„ 6. ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ˜๋ณต๋ฌธ ๊ณ ๊ธ‰ ํ™œ์šฉ

์กฐ๊ฑด๋ฌธ ์ตœ์ ํ™”

# ์‚ผํ•ญ ์—ฐ์‚ฐ์ž
result = value if condition else default

# ๋‹ค์ค‘ ์กฐ๊ฑด
if a < b < c:  # a < b and b < c์™€ ๋™์ผ
    pass

# in ์—ฐ์‚ฐ์ž ํ™œ์šฉ
if x in [1, 2, 3, 4, 5]:  # ๋ฆฌ์ŠคํŠธ๋ณด๋‹ค ์ง‘ํ•ฉ์ด ๋น ๋ฆ„
if x in {1, 2, 3, 4, 5}:  # O(1) vs O(n)

๋ฐ˜๋ณต๋ฌธ ํŒจํ„ด

# enumerate๋กœ ์ธ๋ฑ์Šค์™€ ๊ฐ’ ๋™์‹œ ์ˆœํšŒ
for i, value in enumerate(arr):
    print(f"Index {i}: {value}")

# zip์œผ๋กœ ์—ฌ๋Ÿฌ ๋ฆฌ์ŠคํŠธ ๋™์‹œ ์ˆœํšŒ
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

# range ํ™œ์šฉ
for i in range(10):        # 0~9
for i in range(1, 11):     # 1~10
for i in range(0, 10, 2):  # 0,2,4,6,8

# ์—ญ์ˆœ ๋ฐ˜๋ณต
for i in range(n-1, -1, -1):  # n-1๋ถ€ํ„ฐ 0๊นŒ์ง€
for i in reversed(range(n)):   # ์œ„์™€ ๋™์ผ

๋ฐ˜๋ณต ์ œ์–ด

# break์™€ continue
for i in range(10):
    if i == 3:
        continue  # 3์€ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
    if i == 7:
        break     # 7์—์„œ ์ข…๋ฃŒ
    print(i)

# else์ ˆ ํ™œ์šฉ (break๋กœ ์ข…๋ฃŒ๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ์‹คํ–‰)
for i in range(5):
    if i == 10:  # ์ด ์กฐ๊ฑด์€ ๋งŒ์กฑ๋˜์ง€ ์•Š์Œ
        break
else:
    print("๋ฐ˜๋ณต๋ฌธ์ด ์™„์ „ํžˆ ์ข…๋ฃŒ๋จ")  # ์‹คํ–‰๋จ

โšก 7. ํ•จ์ˆ˜์™€ ๋žŒ๋‹ค ํ‘œํ˜„์‹

ํ•จ์ˆ˜ ์ •์˜์™€ ํ™œ์šฉ

# ๊ธฐ๋ณธ ํ•จ์ˆ˜
def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

# ๊ธฐ๋ณธ๊ฐ’ ๋งค๊ฐœ๋ณ€์ˆ˜
def power(base, exp=2):
    return base ** exp

# ๊ฐ€๋ณ€ ์ธ์ˆ˜
def sum_all(*args):
    return sum(args)

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

๋žŒ๋‹ค ํ‘œํ˜„์‹

# ๊ธฐ๋ณธ ๋žŒ๋‹ค
square = lambda x: x ** 2
add = lambda x, y: x + y

# ์ •๋ ฌ์—์„œ ๋žŒ๋‹ค ํ™œ์šฉ
students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
students.sort(key=lambda x: x[1])  # ์ ์ˆ˜๋กœ ์ •๋ ฌ

# map, filter, reduce์™€ ํ•จ๊ป˜
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))

from functools import reduce
product = reduce(lambda x, y: x * y, numbers)

๋‚ด์žฅ ํ•จ์ˆ˜ ํ™œ์šฉ

# ์ˆ˜ํ•™ ํ•จ์ˆ˜
abs(-5)          # 5
min(1, 2, 3)     # 1
max([1, 2, 3])   # 3
sum([1, 2, 3])   # 6
pow(2, 3)        # 8

# ํ˜•๋ณ€ํ™˜
int('123')       # 123
float('3.14')    # 3.14
str(123)         # '123'
bool(0)          # False

# ์œ ์šฉํ•œ ํ•จ์ˆ˜๋“ค
len([1, 2, 3])   # 3
type(123)        # <class 'int'>
isinstance(123, int)  # True

๐Ÿ›ก๏ธ 8. ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๊ธฐ๋ณธ

try-except ํŒจํ„ด

# ๊ธฐ๋ณธ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
try:
    result = 10 / 0
except ZeroDivisionError:
    result = 0

# ์—ฌ๋Ÿฌ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
try:
    value = int(input())
    result = 10 / value
except (ValueError, ZeroDivisionError) as e:
    print(f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
    result = 0

# else์™€ finally
try:
    file = open('data.txt', 'r')
except FileNotFoundError:
    print("ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")
else:
    data = file.read()  # ์˜ˆ์™ธ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ์‹คํ–‰
finally:
    if 'file' in locals():
        file.close()    # ํ•ญ์ƒ ์‹คํ–‰

PS์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์™ธ์ฒ˜๋ฆฌ

# ์•ˆ์ „ํ•œ ์ž…๋ ฅ ์ฒ˜๋ฆฌ
def safe_input():
    try:
        return int(input())
    except:
        return 0

# ๋ฆฌ์ŠคํŠธ ์ธ๋ฑ์Šค ์•ˆ์ „ ์ ‘๊ทผ
def safe_get(lst, index, default=None):
    try:
        return lst[index]
    except IndexError:
        return default

# ๋”•์…”๋„ˆ๋ฆฌ ์•ˆ์ „ ์ ‘๊ทผ (get() ๋ฉ”์„œ๋“œ๊ฐ€ ๋” ๋‚˜์Œ)
def safe_dict_get(d, key, default=0):
    try:
        return d[key]
    except KeyError:
        return default

๐Ÿ“ 1๋‹จ๊ณ„ ํ•ต์‹ฌ ์š”์•ฝ

๊ผญ ๊ธฐ์–ตํ•ด์•ผ ํ•  ํŒจํ„ด

  1. ๋น ๋ฅธ ์ž…์ถœ๋ ฅ: sys.stdin.readline๊ณผ strip()
  2. ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ: split(), join(), replace()
  3. ๋ฆฌ์ŠคํŠธ ์กฐ์ž‘: ์ปดํ”„๋ฆฌํ—จ์…˜, ์Šฌ๋ผ์ด์‹ฑ, sort() vs sorted()
  4. ๋”•์…”๋„ˆ๋ฆฌ: get(), defaultdict, Counter
  5. ์ง‘ํ•ฉ ์—ฐ์‚ฐ: ์ค‘๋ณต ์ œ๊ฑฐ, ๊ต์ง‘ํ•ฉ/ํ•ฉ์ง‘ํ•ฉ
  6. ๋ฐ˜๋ณต๋ฌธ: enumerate(), zip(), range()

์ž์ฃผ ํ•˜๋Š” ์‹ค์ˆ˜๋“ค

  • 2์ฐจ์› ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ ์‹œ ์–•์€ ๋ณต์‚ฌ
  • ๋ฌธ์ž์—ด ๋ถˆ๋ณ€์„ฑ ๋ฌด์‹œ
  • ๋”•์…”๋„ˆ๋ฆฌ KeyError
  • ๋นˆ ์ง‘ํ•ฉ์„ {}๋กœ ์ƒ์„ฑ
  • input()๊ณผ sys.stdin.readline()์˜ ์ฐจ์ด์ 

ํŒŒ์ด์ฌ PS 2๋‹จ๊ณ„: ๋‹ค๋ฅธ ์–ธ์–ด ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ํŒŒ์ด์ฌ ํŠนํ™” ๊ธฐ๋ฒ•

๐Ÿ”€ 1. ๋ถ„๊ธฐ๋ฌธ๊ณผ ์ œ์–ด๋ฌธ - ํŒŒ์ด์ฌ๋งŒ์˜ ํŠน์ง•

์กฐ๊ฑด๋ฌธ์˜ ํŒŒ์ด์ฌ์Šค๋Ÿฌ์šด ํ‘œํ˜„

์‚ผํ•ญ ์—ฐ์‚ฐ์ž (Ternary Operator)

# ๊ธฐ๋ณธ ํ˜•ํƒœ
result = value_if_true if condition else value_if_false

# ์‹ค์šฉ ์˜ˆ์‹œ
max_val = a if a > b else b
status = "pass" if score >= 60 else "fail"
sign = 1 if num >= 0 else -1

# ์ค‘์ฒฉ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž (๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ)
grade = "A" if score >= 90 else "B" if score >= 80 else "C"

# Java/C++ ๊ฐœ๋ฐœ์ž ์ฃผ์˜: ํŒŒ์ด์ฌ์€ ? : ์—ฐ์‚ฐ์ž๊ฐ€ ์—†์Œ
# Java: int result = condition ? value1 : value2;
# Python: result = value1 if condition else value2

Truthy/Falsy ๊ฐ’ ํ™œ์šฉ

# ํŒŒ์ด์ฌ์—์„œ False๋กœ ํ‰๊ฐ€๋˜๋Š” ๊ฐ’๋“ค
falsy_values = [False, None, 0, 0.0, '', [], {}, set()]

# ์‹ค์šฉ์ ์ธ ํ™œ์šฉ
def process_data(data):
    if not data:  # ๋นˆ ๋ฆฌ์ŠคํŠธ, None, ๋นˆ ๋ฌธ์ž์—ด ๋ชจ๋‘ ์ฒ˜๋ฆฌ
        return "No data"
    return f"Processing {len(data)} items"

# ๊ธฐ๋ณธ๊ฐ’ ์„ค์ • ํŒจํ„ด
name = input_name or "Anonymous"  # input_name์ด ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด "Anonymous"
items = user_items or []          # user_items๊ฐ€ None์ด๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ

# Java/C++๊ณผ ๋‹ค๋ฅธ ์ : 0, ๋นˆ ์ปฌ๋ ‰์…˜๋„ False
# Java: if (list.size() > 0) vs Python: if list:

์ฒด์ด๋‹ ๋น„๊ต (Chained Comparisons)

# ํŒŒ์ด์ฌ๋งŒ์˜ ๋…ํŠนํ•œ ๊ธฐ๋Šฅ
age = 25
if 18 <= age < 65:  # Java/C++: if (age >= 18 && age < 65)
    print("Working age")

# ์—ฌ๋Ÿฌ ์กฐ๊ฑด ์ฒด์ด๋‹
if a < b < c < d:  # ๋ชจ๋“  ๋ถ€๋“ฑํ˜ธ๊ฐ€ ์„ฑ๋ฆฝํ•ด์•ผ ํ•จ
    print("Ascending order")

# ์‹ค์šฉ ์˜ˆ์‹œ
def is_valid_score(score):
    return 0 <= score <= 100

def is_triangle(a, b, c):
    return a + b > c and b + c > a and c + a > b

# ์ฃผ์˜: ๋ณต์žกํ•œ ์ฒด์ด๋‹์€ ๊ฐ€๋…์„ฑ์„ ํ•ด์น  ์ˆ˜ ์žˆ์Œ

match-case ๋ฌธ (Python 3.10+)

# Switch-case์˜ ํŒŒ์ด์ฌ ๋ฒ„์ „
def handle_http_status(status):
    match status:
        case 200:
            return "OK"
        case 404:
            return "Not Found"
        case 500 | 502 | 503:  # ์—ฌ๋Ÿฌ ๊ฐ’ ๋งค์นญ
            return "Server Error"
        case status if 400 <= status < 500:  # ์กฐ๊ฑด๋ถ€ ๋งค์นญ
            return "Client Error"
        case _:  # default case
            return "Unknown Status"

# ํŒจํ„ด ๋งค์นญ ํ™œ์šฉ
def process_data(data):
    match data:
        case []:  # ๋นˆ ๋ฆฌ์ŠคํŠธ
            return "Empty list"
        case [x]:  # ์›์†Œ ํ•˜๋‚˜์ธ ๋ฆฌ์ŠคํŠธ
            return f"Single item: {x}"
        case [x, y]:  # ์›์†Œ ๋‘ ๊ฐœ์ธ ๋ฆฌ์ŠคํŠธ
            return f"Two items: {x}, {y}"
        case [x, *rest]:  # ์ฒซ ๋ฒˆ์งธ ์›์†Œ์™€ ๋‚˜๋จธ์ง€
            return f"First: {x}, Rest: {rest}"
        case {"type": "user", "name": name}:  # ๋”•์…”๋„ˆ๋ฆฌ ํŒจํ„ด
            return f"User: {name}"
        case _:
            return "Unknown pattern"

๐Ÿ”„ 2. ๋ฐ˜๋ณต๋ฌธ - ํŒŒ์ด์ฌ์˜ ๊ฐ•๋ ฅํ•œ ์ดํ„ฐ๋ ˆ์ด์…˜

for๋ฌธ์˜ ๋‹ค์–‘ํ•œ ํ™œ์šฉ

# ๊ธฐ๋ณธ for๋ฌธ (Java/C++์™€ ๋‹ค๋ฅธ ์ )
# Java: for(int i = 0; i < 10; i++)
# Python: for i in range(10)

# ์ธ๋ฑ์Šค์™€ ๊ฐ’ ๋™์‹œ ์ ‘๊ทผ
fruits = ['apple', 'banana', 'cherry']
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")

# ์‹œ์ž‘ ์ธ๋ฑ์Šค ์ง€์ •
for i, fruit in enumerate(fruits, 1):  # 1๋ถ€ํ„ฐ ์‹œ์ž‘
    print(f"{i}: {fruit}")

# ์—ฌ๋Ÿฌ ์‹œํ€€์Šค ๋™์‹œ ์ˆœํšŒ
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"{name} is {age} years old")

# ๊ธธ์ด๊ฐ€ ๋‹ค๋ฅธ ์‹œํ€€์Šค ์ฒ˜๋ฆฌ
from itertools import zip_longest
for name, age in zip_longest(names, ages, fillvalue="Unknown"):
    print(f"{name}: {age}")

range์˜ ๊ณ ๊ธ‰ ํ™œ์šฉ

# ๊ธฐ๋ณธ range ํŒจํ„ด
for i in range(10):        # 0~9
    pass

for i in range(1, 11):     # 1~10
    pass

for i in range(0, 10, 2):  # 0,2,4,6,8 (step=2)
    pass

# ์—ญ์ˆœ ๋ฐ˜๋ณต
for i in range(10, 0, -1):    # 10,9,8,...,1
    pass

for i in reversed(range(10)): # 9,8,7,...,0
    pass

# ์‹ค์šฉ์ ์ธ ํŒจํ„ด๋“ค
# 2์ฐจ์› ๋ฐฐ์—ด ์ˆœํšŒ
matrix = 1,2,3], [4,5,6], [7,8,9">1,2,3], [4,5,6], [7,8,9
for i in range(len(matrix)):
    for j in range(len(matrix[i])):
        print(matrix[i][j])

# ๋” ํŒŒ์ด์ฌ์Šค๋Ÿฌ์šด ๋ฐฉ๋ฒ•
for row in matrix:
    for cell in row:
        print(cell)

# ์ธ๋ฑ์Šค๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ
for i, row in enumerate(matrix):
    for j, cell in enumerate(row):
        print(f"matrix[{i}][{j}] = {cell}")

while๋ฌธ๊ณผ ์ œ์–ด

# while-else ํŒจํ„ด (๋‹ค๋ฅธ ์–ธ์–ด์— ์—†๋Š” ๊ธฐ๋Šฅ)
def find_factor(n):
    i = 2
    while i * i <= n:
        if n % i == 0:
            print(f"Found factor: {i}")
            break
        i += 1
    else:  # break๋กœ ๋น ์ ธ๋‚˜์˜ค์ง€ ์•Š์•˜์„ ๋•Œ ์‹คํ–‰
        print(f"{n} is prime")

# for-else๋„ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™
def search_item(items, target):
    for item in items:
        if item == target:
            print(f"Found {target}")
            break
    else:
        print(f"{target} not found")

# ๋ฌดํ•œ๋ฃจํ”„ ํŒจํ„ด
while True:
    user_input = input("Enter command (quit to exit): ")
    if user_input == "quit":
        break
    process_command(user_input)

๐Ÿฌ 3. ์Šˆ๊ฐ€ ์‹ ํƒ์Šค (Syntactic Sugar)

๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜์˜ ๊ณ ๊ธ‰ ํ™œ์šฉ

# ๊ธฐ๋ณธ ์ปดํ”„๋ฆฌํ—จ์…˜
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]

# ์ค‘์ฒฉ ๋ฃจํ”„ ์ปดํ”„๋ฆฌํ—จ์…˜
matrix = [[i+j for j in range(3)] for i in range(3)]
# ๊ฒฐ๊ณผ: 0,1,2], [1,2,3], [2,3,4

# ์กฐ๊ฑด๋ถ€ ํ‘œํ˜„์‹๊ณผ ํ•จ๊ป˜
result = [x if x > 0 else 0 for x in [-1, 2, -3, 4]]

# ๋ณต์žกํ•œ ์กฐ๊ฑด
filtered = [x for x in range(100) 
           if x % 2 == 0 and x % 3 == 0 and x > 10]

# ์ค‘์ฒฉ ๋ฆฌ์ŠคํŠธ ํ‰ํƒ„ํ™”
nested = 1, 2], [3, 4], [5, 6">1, 2], [3, 4], [5, 6
flattened = [item for sublist in nested for item in sublist]
# ๊ฒฐ๊ณผ: [1, 2, 3, 4, 5, 6]

# ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ
words = ["hello", "world", "python"]
lengths = [len(word) for word in words]
capitals = [word.upper() for word in words if len(word) > 4]

๋”•์…”๋„ˆ๋ฆฌ์™€ ์ง‘ํ•ฉ ์ปดํ”„๋ฆฌํ—จ์…˜

# ๋”•์…”๋„ˆ๋ฆฌ ์ปดํ”„๋ฆฌํ—จ์…˜
squares_dict = {x: x**2 for x in range(5)}
# ๊ฒฐ๊ณผ: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# ์กฐ๊ฑด๋ถ€ ๋”•์…”๋„ˆ๋ฆฌ ์ปดํ”„๋ฆฌํ—จ์…˜
word_lengths = {word: len(word) for word in words if len(word) > 3}

# ๋”•์…”๋„ˆ๋ฆฌ ๋ณ€ํ™˜
original = {'a': 1, 'b': 2, 'c': 3}
reversed_dict = {v: k for k, v in original.items()}

# ์ง‘ํ•ฉ ์ปดํ”„๋ฆฌํ—จ์…˜
unique_lengths = {len(word) for word in words}

# ์‹ค์šฉ์ ์ธ ์˜ˆ์‹œ: ๋‹จ์–ด ๋นˆ๋„ ๊ณ„์‚ฐ
text = "hello world hello python world"
word_count = {word: text.split().count(word) for word in set(text.split())}

์–ธํŒจํ‚น๊ณผ ํŒจํ‚น

# ๊ธฐ๋ณธ ์–ธํŒจํ‚น
point = (3, 4)
x, y = point

# ํ™•์žฅ ์–ธํŒจํ‚น (Python 3+)
numbers = [1, 2, 3, 4, 5]
first, *middle, last = numbers  # first=1, middle=[2,3,4], last=5
first, second, *rest = numbers  # first=1, second=2, rest=[3,4,5]

# ํ•จ์ˆ˜ ์ธ์ˆ˜ ์–ธํŒจํ‚น
def greet(name, age, city):
    print(f"Hello {name}, {age} years old from {city}")

person = ("Alice", 25, "Seoul")
greet(*person)  # ํŠœํ”Œ ์–ธํŒจํ‚น

person_dict = {"name": "Bob", "age": 30, "city": "Busan"}
greet(**person_dict)  # ๋”•์…”๋„ˆ๋ฆฌ ์–ธํŒจํ‚น

# ๋ณ€์ˆ˜ ๊ตํ™˜
a, b = b, a  # Java/C++: temp = a; a = b; b = temp;

# ์—ฌ๋Ÿฌ ๋ณ€์ˆ˜ ๋™์‹œ ํ• ๋‹น
a = b = c = 0
x, y, z = 1, 2, 3

Walrus ์—ฐ์‚ฐ์ž (:=) - Python 3.8+

# ํ• ๋‹น๊ณผ ๋™์‹œ์— ์กฐ๊ฑด ๊ฒ€์‚ฌ
if (n := len(some_list)) > 10:
    print(f"List is too long ({n} elements)")

# while ๋ฃจํ”„์—์„œ ์œ ์šฉ
while (line := input("Enter something: ")) != "quit":
    print(f"You entered: {line}")

# ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜์—์„œ ์ค‘๋ณต ๊ณ„์‚ฐ ๋ฐฉ์ง€
# ๋‚˜์œ ์˜ˆ: expensive_function์ด ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋จ
results = [expensive_function(x) for x in data if expensive_function(x) > 0]

# ์ข‹์€ ์˜ˆ: walrus ์—ฐ์‚ฐ์ž๋กœ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ
results = [y for x in data if (y := expensive_function(x)) > 0]

๐Ÿ 4. ํŒŒ์ด์ฌ ํŠน์ง•์ ์ธ ๋ถ€๋ถ„๋“ค

๋™์  ํƒ€์ดํ•‘์˜ ํ™œ์šฉ

# ๊ฐ™์€ ๋ณ€์ˆ˜์— ๋‹ค๋ฅธ ํƒ€์ž… ํ• ๋‹น ๊ฐ€๋Šฅ (Java/C++์™€ ๋‹ค๋ฆ„)
var = 42          # int
var = "hello"     # str
var = [1, 2, 3]   # list

# ํƒ€์ž… ํžŒํŠธ (Python 3.5+) - ์‹คํ–‰์—๋Š” ์˜ํ–ฅ ์—†์Œ
def greet(name: str, age: int) -> str:
    return f"Hello {name}, you are {age} years old"

# isinstance๋ฅผ ์ด์šฉํ•œ ํƒ€์ž… ์ฒดํฌ
def process_input(data):
    if isinstance(data, str):
        return data.upper()
    elif isinstance(data, list):
        return len(data)
    elif isinstance(data, (int, float)):  # ์—ฌ๋Ÿฌ ํƒ€์ž… ์ฒดํฌ
        return data * 2
    else:
        return None

# ๋• ํƒ€์ดํ•‘ (Duck Typing)
def print_items(container):
    # ๋ฆฌ์ŠคํŠธ๋“  ํŠœํ”Œ์ด๋“  ๋ฌธ์ž์—ด์ด๋“  ์ดํ„ฐ๋Ÿฌ๋ธ”์ด๋ฉด ์ž‘๋™
    for item in container:
        print(item)

๋‹ค์ค‘ ํ• ๋‹น๊ณผ ํŠน์ˆ˜ํ•œ ๊ฐ’๋“ค

# None ๊ฐ’ ์ฒ˜๋ฆฌ (Java์˜ null๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋‹ค๋ฆ„)
def safe_divide(a, b):
    return a / b if b != 0 else None

result = safe_divide(10, 0)
if result is not None:  # == None์ด ์•„๋‹Œ is๋ฅผ ์‚ฌ์šฉ
    print(f"Result: {result}")

# ๋‹ค์ค‘ ํ• ๋‹น์˜ ํ™œ์šฉ
def get_min_max(numbers):
    return min(numbers), max(numbers)

min_val, max_val = get_min_max([1, 5, 3, 9, 2])

# ์–ธ๋”์Šค์ฝ”์–ด๋กœ ๋ฌด์‹œํ•  ๊ฐ’ ํ‘œ์‹œ
_, max_val = get_min_max(numbers)  # ์ตœ์†Ÿ๊ฐ’ ๋ฌด์‹œ
first, _, third = (1, 2, 3)       # ๋‘ ๋ฒˆ์งธ ๊ฐ’ ๋ฌด์‹œ

๋ฉ”์„œ๋“œ ์ฒด์ด๋‹๊ณผ fluent interface

# ๋ฌธ์ž์—ด ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹
text = "  Hello World  "
result = text.strip().lower().replace(" ", "_")
# ๊ฒฐ๊ณผ: "hello_world"

# ๋ฆฌ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋Š” ์ฒด์ด๋‹ ๋ถˆ๊ฐ€ (๋Œ€๋ถ€๋ถ„ None ๋ฐ˜ํ™˜)
# ๋‚˜์œ ์˜ˆ
# numbers = [3, 1, 4, 1, 5].sort().reverse()  # AttributeError!

# ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ
numbers = [3, 1, 4, 1, 5]
numbers.sort()
numbers.reverse()

# ๋˜๋Š” ํ•จ์ˆ˜ํ˜• ์Šคํƒ€์ผ
numbers = sorted([3, 1, 4, 1, 5], reverse=True)

์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ € (with ๋ฌธ)

# ํŒŒ์ผ ์ฒ˜๋ฆฌ (์ž๋™์œผ๋กœ ํŒŒ์ผ ๋‹ซ๊ธฐ)
with open('data.txt', 'r') as f:
    content = f.read()
# ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ๋‹ซํž˜

# ์—ฌ๋Ÿฌ ํŒŒ์ผ ๋™์‹œ ์ฒ˜๋ฆฌ
with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
    outfile.write(infile.read().upper())

# ์ปค์Šคํ…€ ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ €
from contextlib import contextmanager

@contextmanager
def timer():
    import time
    start = time.time()
    print("Timer started")
    try:
        yield
    finally:
        end = time.time()
        print(f"Elapsed time: {end - start:.2f}s")

# ์‚ฌ์šฉ
with timer():
    # ์‹œ๊ฐ„์„ ์ธก์ •ํ•  ์ฝ”๋“œ
    time.sleep(1)

๐Ÿ”ง 5. ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๋žŒ๋‹ค

๋žŒ๋‹ค ํ•จ์ˆ˜์˜ ๋‹ค์–‘ํ•œ ํ™œ์šฉ

# ๊ธฐ๋ณธ ๋žŒ๋‹ค
square = lambda x: x ** 2
add = lambda x, y: x + y

# ์ •๋ ฌ์—์„œ ๋žŒ๋‹ค ํ™œ์šฉ
students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]

# ์ด๋ฆ„์œผ๋กœ ์ •๋ ฌ
students.sort(key=lambda student: student[0])

# ์ ์ˆ˜๋กœ ์ •๋ ฌ (๋‚ด๋ฆผ์ฐจ์ˆœ)
students.sort(key=lambda student: student[1], reverse=True)

# ๋ณต์žกํ•œ ์ •๋ ฌ ๊ธฐ์ค€
data = [('A', 1, 100), ('B', 2, 85), ('A', 3, 95)]
# ์ฒซ ๋ฒˆ์งธ ํ•„๋“œ๋กœ ์ •๋ ฌ, ๊ฐ™์œผ๋ฉด ์„ธ ๋ฒˆ์งธ ํ•„๋“œ๋กœ ์ •๋ ฌ
data.sort(key=lambda x: (x[0], x[2]))

# ์กฐ๊ฑด๋ถ€ ๋žŒ๋‹ค
get_grade = lambda score: 'A' if score >= 90 else 'B' if score >= 80 else 'C'

map, filter, reduce ํ•จ์ˆ˜ํ˜• ํŒจํ„ด

# map: ๋ชจ๋“  ์š”์†Œ์— ํ•จ์ˆ˜ ์ ์šฉ
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
# ๊ฒฐ๊ณผ: [1, 4, 9, 16, 25]

# ์—ฌ๋Ÿฌ ์‹œํ€€์Šค์— ์ ์šฉ
nums1 = [1, 2, 3]
nums2 = [4, 5, 6]
sums = list(map(lambda x, y: x + y, nums1, nums2))
# ๊ฒฐ๊ณผ: [5, 7, 9]

# filter: ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ๋งŒ ์„ ํƒ
evens = list(filter(lambda x: x % 2 == 0, numbers))
# ๊ฒฐ๊ณผ: [2, 4]

# reduce: ๋ˆ„์  ์—ฐ์‚ฐ
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)  # 1*2*3*4*5 = 120
max_val = reduce(lambda x, y: x if x > y else y, numbers)

# ์‹ค์šฉ์ ์ธ ์˜ˆ์‹œ: ๋‹จ์–ด์—์„œ ๋ชจ์Œ ์ œ๊ฑฐ
def remove_vowels(text):
    vowels = "aeiouAEIOU"
    return ''.join(filter(lambda char: char not in vowels, text))

# ์ค‘์ฒฉ ํ•จ์ˆ˜์™€ ํด๋กœ์ €
def make_multiplier(n):
    return lambda x: x * n

double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5))  # 10
print(triple(5))  # 15

๊ณ ์ฐจ ํ•จ์ˆ˜ ํŒจํ„ด

# ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜
def apply_operation(numbers, operation):
    return [operation(x) for x in numbers]

# ์‚ฌ์šฉ ์˜ˆ์‹œ
result1 = apply_operation([1, 2, 3, 4], lambda x: x**2)
result2 = apply_operation([1, 2, 3, 4], lambda x: x * 2)

# ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
def create_validator(min_val, max_val):
    def validator(value):
        return min_val <= value <= max_val
    return validator

age_validator = create_validator(0, 120)
score_validator = create_validator(0, 100)

# ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ณธ ์ดํ•ด
def timing_decorator(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.4f}s")
        return result
    return wrapper

@timing_decorator
def slow_function():
    import time
    time.sleep(1)
    return "Done"

๐Ÿ“Š 6. ์ž๋ฃŒ๊ตฌ์กฐ ์œ ์šฉํ•œ ํŒจํ„ด๋“ค

๋”•์…”๋„ˆ๋ฆฌ ๊ณ ๊ธ‰ ํŒจํ„ด

# ํŒจํ„ด 1: ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉด ๊ฐ’ ์ฆ๊ฐ€, ์—†์œผ๋ฉด 1๋กœ ์„ค์ •
# ๋ฐฉ๋ฒ• 1: get() ์‚ฌ์šฉ
count = {}
for item in items:
    count[item] = count.get(item, 0) + 1

# ๋ฐฉ๋ฒ• 2: setdefault() ์‚ฌ์šฉ
count = {}
for item in items:
    count.setdefault(item, 0)
    count[item] += 1

# ๋ฐฉ๋ฒ• 3: defaultdict ์‚ฌ์šฉ (๊ฐ€์žฅ ๊น”๋”)
from collections import defaultdict
count = defaultdict(int)
for item in items:
    count[item] += 1

# ๋ฐฉ๋ฒ• 4: Counter ์‚ฌ์šฉ (๊ฐ€์žฅ ํŒŒ์ด์ฌ์Šค๋Ÿฌ์›€)
from collections import Counter
count = Counter(items)

# ํŒจํ„ด 2: ๊ทธ๋ฃนํ•‘
# ํ•™์ƒ๋“ค์„ ์„ฑ์ ๋ณ„๋กœ ๊ทธ๋ฃนํ•‘
students = [('Alice', 'A'), ('Bob', 'B'), ('Charlie', 'A'), ('David', 'B')]

# defaultdict๋กœ ๊ทธ๋ฃนํ•‘
from collections import defaultdict
groups = defaultdict(list)
for name, grade in students:
    groups[grade].append(name)
# ๊ฒฐ๊ณผ: {'A': ['Alice', 'Charlie'], 'B': ['Bob', 'David']}

# itertools.groupby ์‚ฌ์šฉ (์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ)
from itertools import groupby
students.sort(key=lambda x: x[1])  # ์„ฑ์ ์œผ๋กœ ์ •๋ ฌ ๋จผ์ €
groups = {grade: [name for name, _ in group] 
          for grade, group in groupby(students, key=lambda x: x[1])}

๋ฆฌ์ŠคํŠธ์™€ ํ, ์Šคํƒ ํŒจํ„ด

# ์Šคํƒ ํŒจํ„ด (LIFO)
stack = []
stack.append(1)    # push
stack.append(2)
item = stack.pop() # pop (2)

# ํ ํŒจํ„ด (FIFO) - deque ์‚ฌ์šฉ ๊ถŒ์žฅ
from collections import deque
queue = deque()
queue.append(1)      # enqueue
queue.append(2)
item = queue.popleft()  # dequeue (1)

# ์šฐ์„ ์ˆœ์œ„ ํ
import heapq
heap = []
heapq.heappush(heap, (priority, item))
priority, item = heapq.heappop(heap)

# ์ตœ๋Œ€ ํž™ ๊ตฌํ˜„ (์Œ์ˆ˜ ์ด์šฉ)
max_heap = []
heapq.heappush(max_heap, -value)
max_value = -heapq.heappop(max_heap)

# ๋ฆฌ์ŠคํŠธ์˜ ๊ณ ๊ธ‰ ์กฐ์ž‘
# ํŠน์ • ์กฐ๊ฑด์˜ ๋ชจ๋“  ์š”์†Œ ์ œ๊ฑฐ
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# ํ™€์ˆ˜๋งŒ ๋‚จ๊ธฐ๊ธฐ
numbers = [x for x in numbers if x % 2 == 1]

# ๋˜๋Š” filter ์‚ฌ์šฉ
numbers = list(filter(lambda x: x % 2 == 1, numbers))

# ๋ฆฌ์ŠคํŠธ์—์„œ ์ค‘๋ณต ์ œ๊ฑฐ (์ˆœ์„œ ์œ ์ง€)
def remove_duplicates(lst):
    seen = set()
    result = []
    for item in lst:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

# ๋˜๋Š” dict.fromkeys() ํŠธ๋ฆญ (Python 3.7+)
unique_list = list(dict.fromkeys(original_list))

์ง‘ํ•ฉ ์—ฐ์‚ฐ ๊ณ ๊ธ‰ ํ™œ์šฉ

# ์ง‘ํ•ฉ์˜ ๊ฐ•๋ ฅํ•œ ์—ฐ์‚ฐ๋“ค
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# ๊ต์ง‘ํ•ฉ: ๊ณตํ†ต ์›์†Œ
common = set1 & set2  # {4, 5}

# ํ•ฉ์ง‘ํ•ฉ: ๋ชจ๋“  ์›์†Œ
all_items = set1 | set2  # {1, 2, 3, 4, 5, 6, 7, 8}

# ์ฐจ์ง‘ํ•ฉ: set1์—๋งŒ ์žˆ๋Š” ์›์†Œ
only_in_set1 = set1 - set2  # {1, 2, 3}

# ๋Œ€์นญ์ฐจ์ง‘ํ•ฉ: ๋‘˜ ์ค‘ ํ•˜๋‚˜์—๋งŒ ์žˆ๋Š” ์›์†Œ
symmetric_diff = set1 ^ set2  # {1, 2, 3, 6, 7, 8}

# ์‹ค์šฉ์ ์ธ ํ™œ์šฉ: ๋‘ ๋ฆฌ์ŠคํŠธ์˜ ๊ณตํ†ต ์›์†Œ ์ฐพ๊ธฐ
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common_elements = list(set(list1) & set(list2))

# ์ค‘๋ณต ์›์†Œ ์ฐพ๊ธฐ
def find_duplicates(lst):
    seen = set()
    duplicates = set()
    for item in lst:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    return list(duplicates)

collections ๋ชจ๋“ˆ์˜ ํŠน์ˆ˜ ์ž๋ฃŒ๊ตฌ์กฐ

from collections import namedtuple, OrderedDict, ChainMap

# namedtuple: ํ•„๋“œ๋ช…์ด ์žˆ๋Š” ํŠœํ”Œ
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y)  # 3 4
print(p[0], p[1])  # 3 4 (์ธ๋ฑ์Šค๋กœ๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ)

# Student ์˜ˆ์‹œ
Student = namedtuple('Student', ['name', 'age', 'grade'])
alice = Student('Alice', 20, 'A')
print(f"{alice.name} got {alice.grade}")

# OrderedDict: ์‚ฝ์ž… ์ˆœ์„œ ์œ ์ง€ (Python 3.7+์—์„œ๋Š” ์ผ๋ฐ˜ dict๋„ ์ˆœ์„œ ์œ ์ง€)
from collections import OrderedDict
ordered = OrderedDict()
ordered['first'] = 1
ordered['second'] = 2
ordered['third'] = 3

# ChainMap: ์—ฌ๋Ÿฌ ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ํ•˜๋‚˜์ฒ˜๋Ÿผ ์‚ฌ์šฉ
default_config = {'timeout': 30, 'retries': 3}
user_config = {'timeout': 60}
config = ChainMap(user_config, default_config)
print(config['timeout'])  # 60 (user_config๊ฐ€ ์šฐ์„ )
print(config['retries'])  # 3 (default_config์—์„œ)

๐ŸŽฏ 7. ์‹ค์ „ ํ™œ์šฉ ํŒจํ„ด ๋ชจ์Œ

ํŒŒ์ผ ์ฒ˜๋ฆฌ ํŒจํ„ด

# ํŒŒ์ผ ์ฝ๊ธฐ ํŒจํ„ด๋“ค
# ์ „์ฒด ํŒŒ์ผ ์ฝ๊ธฐ
with open('file.txt', 'r', encoding='utf-8') as f:
    content = f.read()

# ์ค„ ๋‹จ์œ„๋กœ ์ฝ๊ธฐ
with open('file.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()  # ๊ฐœํ–‰๋ฌธ์ž ํฌํ•จ
    lines = [line.strip() for line in lines]  # ๊ฐœํ–‰๋ฌธ์ž ์ œ๊ฑฐ

# ํ•œ ์ค„์”ฉ ์ฒ˜๋ฆฌ (๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ )
with open('file.txt', 'r', encoding='utf-8') as f:
    for line in f:
        process_line(line.strip())

# CSV ์ฒ˜๋ฆฌ
import csv
with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['name'], row['age'])

์—๋Ÿฌ ์ฒ˜๋ฆฌ ํŒจํ„ด

# ๊ธฐ๋ณธ try-except ํŒจํ„ด
try:
    result = risky_operation()
except SpecificError as e:
    handle_specific_error(e)
except (ErrorType1, ErrorType2) as e:
    handle_multiple_errors(e)
except Exception as e:
    handle_generic_error(e)
else:
    # ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์„ ๋•Œ
    success_handler(result)
finally:
    # ํ•ญ์ƒ ์‹คํ–‰
    cleanup()

# EAFP (Easier to Ask for Forgiveness than Permission) ํŒจํ„ด
# ํŒŒ์ด์ฌ์Šค๋Ÿฌ์šด ๋ฐฉ๋ฒ•
try:
    return my_dict[key]
except KeyError:
    return default_value

# vs LBYL (Look Before You Leap) - ๋œ ํŒŒ์ด์ฌ์Šค๋Ÿฌ์›€
if key in my_dict:
    return my_dict[key]
else:
    return default_value

์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

# ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ ์ตœ์ ํ™”
# ๋‚˜์œ ์˜ˆ (O(nยฒ))
result = ""
for word in words:
    result += word + " "

# ์ข‹์€ ์˜ˆ (O(n))
result = " ".join(words)

# ๋ฆฌ์ŠคํŠธ ๋‚ดํฌ vs map/filter
# ๋ฆฌ์ŠคํŠธ ๋‚ดํฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ๋น ๋ฆ„
squares1 = [x**2 for x in range(1000)]
squares2 = list(map(lambda x: x**2, range(1000)))

# ์ง‘ํ•ฉ ๋ฉค๋ฒ„์‹ญ ํ…Œ์ŠคํŠธ
# ๋ฆฌ์ŠคํŠธ: O(n), ์ง‘ํ•ฉ: O(1)
large_list = list(range(10000))
large_set = set(range(10000))

# ๋А๋ฆผ
if 9999 in large_list:
    pass

# ๋น ๋ฆ„
if 9999 in large_set:
    pass

# ๋”•์…”๋„ˆ๋ฆฌ vs ๋ฆฌ์ŠคํŠธ ๊ฒ€์ƒ‰
# key๋กœ ๊ฒ€์ƒ‰ํ•  ๋•Œ๋Š” ๋”•์…”๋„ˆ๋ฆฌ๊ฐ€ ํ›จ์”ฌ ๋น ๋ฆ„
data_dict = {i: f"value_{i}" for i in range(1000)}
data_list = [(i, f"value_{i}") for i in range(1000)]

๐Ÿ“ 3๋‹จ๊ณ„ ํ•ต์‹ฌ ์š”์•ฝ

Java/C++ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฃผ์˜ํ•  ์ 

  1. ํƒ€์ž… ์‹œ์Šคํ…œ: ๋™์  ํƒ€์ดํ•‘, isinstance() ํ™œ์šฉ
  2. ๋ฐ˜๋ณต๋ฌธ: range() ์‚ฌ์šฉ๋ฒ•, enumerate/zip ํ™œ์šฉ
  3. ์กฐ๊ฑด๋ฌธ: Truthy/Falsy ๊ฐœ๋…, ์ฒด์ด๋‹ ๋น„๊ต
  4. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ: ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ์ž๋™, with๋ฌธ ํ™œ์šฉ

ํŒŒ์ด์ฌ๋‹ค์šด ์ฝ”๋”ฉ ์Šคํƒ€์ผ

  1. EAFP over LBYL: ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์šฐ์„ 
  2. ์ปดํ”„๋ฆฌํ—จ์…˜ ํ™œ์šฉ: ๋ฆฌ์ŠคํŠธ/๋”•์…”๋„ˆ๋ฆฌ/์ง‘ํ•ฉ ์ปดํ”„๋ฆฌํ—จ์…˜
  3. ์–ธํŒจํ‚น ํ™œ์šฉ: ํŠœํ”Œ/๋”•์…”๋„ˆ๋ฆฌ ์–ธํŒจํ‚น
  4. ๋‚ด์žฅ ํ•จ์ˆ˜ ํ™œ์šฉ: map, filter, zip, enumerate

์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • collections.Counter๋กœ ๋นˆ๋„ ๊ณ„์‚ฐ
  • collections.defaultdict๋กœ ๊ทธ๋ฃนํ•‘
  • enumerate()๋กœ ์ธ๋ฑ์Šค์™€ ๊ฐ’ ๋™์‹œ ์ ‘๊ทผ
  • zip()์œผ๋กœ ์—ฌ๋Ÿฌ ์‹œํ€€์Šค ๋™์‹œ ์ˆœํšŒ
  • ๋ฆฌ์ŠคํŠธ ์ปดํ”„๋ฆฌํ—จ์…˜์œผ๋กœ ๋ณ€ํ™˜๊ณผ ํ•„ํ„ฐ๋ง
  • any()/all()๋กœ ์กฐ๊ฑด ๊ฒ€์‚ฌ
  • *args/**kwargs๋กœ ๊ฐ€๋ณ€ ์ธ์ˆ˜ ์ฒ˜๋ฆฌ

ํŒŒ์ด์ฌ PS 3๋‹จ๊ณ„: PS ํ•ต์‹ฌ ํŒจํ„ด

๐Ÿ” 1. ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (DFS/BFS ํ…œํ”Œ๋ฆฟ)

DFS (๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰)

์žฌ๊ท€์  DFS

def dfs_recursive(graph, start, visited=None):
    if visited is None:
        visited = set()
    
    visited.add(start)
    print(start)  # ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ
    
    for neighbor in graph[start]:
        if neighbor not in visited:
            dfs_recursive(graph, neighbor, visited)
    
    return visited

# ์‚ฌ์šฉ ์˜ˆ์‹œ
graph = {
    'A': ['B', 'C'],
    'B': ['A', 'D', 'E'],
    'C': ['A', 'F'],
    'D': ['B'],
    'E': ['B', 'F'],
    'F': ['C', 'E']
}

์Šคํƒ์„ ์ด์šฉํ•œ DFS

def dfs_iterative(graph, start):
    visited = set()
    stack = [start]
    
    while stack:
        vertex = stack.pop()
        if vertex not in visited:
            visited.add(vertex)
            print(vertex)  # ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ
            
            # ์—ญ์ˆœ์œผ๋กœ ์ถ”๊ฐ€ (์žฌ๊ท€์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๋ฐฉ๋ฌธํ•˜๊ธฐ ์œ„ํ•ด)
            for neighbor in reversed(graph[vertex]):
                if neighbor not in visited:
                    stack.append(neighbor)
    
    return visited

2์ฐจ์› ๊ฒฉ์ž์—์„œ DFS

def dfs_grid(grid, start_row, start_col, visited):
    rows, cols = len(grid), len(grid[0])
    
    # ๊ฒฝ๊ณ„ ์ฒดํฌ ๋ฐ ๋ฐฉ๋ฌธ ์ฒดํฌ
    if (start_row < 0 or start_row >= rows or 
        start_col < 0 or start_col >= cols or
        visited[start_row][start_col] or 
        grid[start_row][start_col] == 0):  # 0์€ ๋ฒฝ์ด๋ผ ๊ฐ€์ •
        return
    
    visited[start_row][start_col] = True
    print(f"๋ฐฉ๋ฌธ: ({start_row}, {start_col})")
    
    # 4๋ฐฉํ–ฅ ํƒ์ƒ‰ (์ƒ, ํ•˜, ์ขŒ, ์šฐ)
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    for dr, dc in directions:
        dfs_grid(grid, start_row + dr, start_col + dc, visited)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
grid = [
    [1, 1, 0, 1],
    [1, 0, 1, 1],
    [0, 1, 1, 1],
    [1, 1, 1, 0]
]
visited = [[False] * len(grid[0]) for _ in range(len(grid))]

BFS (๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰)

๊ธฐ๋ณธ BFS

from collections import deque

def bfs(graph, start):
    visited = set()
    queue = deque([start])
    visited.add(start)
    
    while queue:
        vertex = queue.popleft()
        print(vertex)  # ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ
        
        for neighbor in graph[vertex]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)
    
    return visited

์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•˜๋Š” BFS

def bfs_shortest_path(graph, start, end):
    visited = set()
    queue = deque([(start, 0)])  # (๋…ธ๋“œ, ๊ฑฐ๋ฆฌ)
    visited.add(start)
    
    while queue:
        vertex, distance = queue.popleft()
        
        if vertex == end:
            return distance
        
        for neighbor in graph[vertex]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append((neighbor, distance + 1))
    
    return -1  # ๊ฒฝ๋กœ๊ฐ€ ์—†์Œ

2์ฐจ์› ๊ฒฉ์ž์—์„œ BFS

def bfs_grid(grid, start_row, start_col):
    rows, cols = len(grid), len(grid[0])
    visited = [[False] * cols for _ in range(rows)]
    queue = deque([(start_row, start_col, 0)])  # (ํ–‰, ์—ด, ๊ฑฐ๋ฆฌ)
    visited[start_row][start_col] = True
    
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    
    while queue:
        row, col, dist = queue.popleft()
        print(f"๋ฐฉ๋ฌธ: ({row}, {col}), ๊ฑฐ๋ฆฌ: {dist}")
        
        for dr, dc in directions:
            new_row, new_col = row + dr, col + dc
            
            if (0 <= new_row < rows and 0 <= new_col < cols and
                not visited[new_row][new_col] and 
                grid[new_row][new_col] == 1):  # 1์€ ์ด๋™ ๊ฐ€๋Šฅํ•œ ์นธ
                
                visited[new_row][new_col] = True
                queue.append((new_row, new_col, dist + 1))

๐Ÿšจ DFS/BFS ์ฃผ์š” ํ•จ์ •

  • ์žฌ๊ท€ DFS์˜ ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ (Python ๊ธฐ๋ณธ ์žฌ๊ท€ ํ•œ๋„: 1000)
  • sys.setrecursionlimit(10**6) ์„ค์ • ํ•„์š”ํ•œ ๊ฒฝ์šฐ
  • BFS์—์„œ deque ์‚ฌ์šฉ ํ•„์ˆ˜ (list์˜ pop(0)์€ O(n))
  • ๋ฐฉ๋ฌธ ์ฒดํฌ๋ฅผ ํ์— ๋„ฃ์„ ๋•Œ vs ํ์—์„œ ๋บ„ ๋•Œ์˜ ์ฐจ์ด์ 

๐Ÿ“Š 2. ์ •๋ ฌ๊ณผ ์ด์ง„ํƒ์ƒ‰ ํŒจํ„ด

๋‹ค์–‘ํ•œ ์ •๋ ฌ ๊ธฐ๋ฒ•

๊ธฐ๋ณธ ์ •๋ ฌ

# ๋ฆฌ์ŠคํŠธ ์ •๋ ฌ
arr = [3, 1, 4, 1, 5, 9, 2, 6]
arr.sort()                    # ์›๋ณธ ์ˆ˜์ •
sorted_arr = sorted(arr)      # ์ƒˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜

# ์—ญ์ˆœ ์ •๋ ฌ
arr.sort(reverse=True)

์ปค์Šคํ…€ ์ •๋ ฌ

# ํŠœํ”Œ ์ •๋ ฌ (์—ฌ๋Ÿฌ ๊ธฐ์ค€)
students = [('Alice', 85, 20), ('Bob', 90, 19), ('Charlie', 85, 21)]

# ์ ์ˆ˜ ๋‚ด๋ฆผ์ฐจ์ˆœ, ๊ฐ™์œผ๋ฉด ๋‚˜์ด ์˜ค๋ฆ„์ฐจ์ˆœ
students.sort(key=lambda x: (-x[1], x[2]))

# ๋ฌธ์ž์—ด ๊ธธ์ด๋กœ ์ •๋ ฌ
words = ['apple', 'pie', 'banana', 'book']
words.sort(key=len)

# ์ ˆ๋Œ“๊ฐ’์œผ๋กœ ์ •๋ ฌ
numbers = [-3, -1, 4, -5, 2]
numbers.sort(key=abs)

์•ˆ์ • ์ •๋ ฌ vs ๋ถˆ์•ˆ์ • ์ •๋ ฌ

# Python์˜ sort()๋Š” stable sort (๊ฐ™์€ ๊ฐ’์˜ ์›๋ž˜ ์ˆœ์„œ ์œ ์ง€)
data = [('A', 1), ('B', 2), ('C', 1), ('D', 2)]
data.sort(key=lambda x: x[1])
# ๊ฒฐ๊ณผ: [('A', 1), ('C', 1), ('B', 2), ('D', 2)]
# A์™€ C์˜ ์ˆœ์„œ, B์™€ D์˜ ์ˆœ์„œ๊ฐ€ ์œ ์ง€๋จ

๊ธฐ๋ณธ ์ด์ง„ํƒ์ƒ‰

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2
        
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    
    return -1  # ์ฐพ์ง€ ๋ชปํ•จ

# ๋‚ด์žฅ ํ•จ์ˆ˜ ์‚ฌ์šฉ
import bisect
arr = [1, 3, 5, 7, 9]
index = bisect.bisect_left(arr, 5)  # 5๊ฐ€ ๋“ค์–ด๊ฐˆ ์œ„์น˜

Lower Bound / Upper Bound

def lower_bound(arr, target):
    """target ์ด์ƒ์ธ ์ฒซ ๋ฒˆ์งธ ์›์†Œ์˜ ์ธ๋ฑ์Šค"""
    left, right = 0, len(arr)
    
    while left < right:
        mid = (left + right) // 2
        if arr[mid] < target:
            left = mid + 1
        else:
            right = mid
    
    return left

def upper_bound(arr, target):
    """target ์ดˆ๊ณผ์ธ ์ฒซ ๋ฒˆ์งธ ์›์†Œ์˜ ์ธ๋ฑ์Šค"""
    left, right = 0, len(arr)
    
    while left < right:
        mid = (left + right) // 2
        if arr[mid] <= target:
            left = mid + 1
        else:
            right = mid
    
    return left

# bisect ๋ชจ๋“ˆ ํ™œ์šฉ
import bisect
arr = [1, 2, 2, 2, 3, 4, 5]
lower = bisect.bisect_left(arr, 2)   # 1
upper = bisect.bisect_right(arr, 2)  # 4
count = upper - lower                # 2์˜ ๊ฐœ์ˆ˜: 3
def parametric_search(check_function, left, right):
    """
    check_function(x)๊ฐ€ True๊ฐ€ ๋˜๋Š” ์ตœ์†Œ๊ฐ’์„ ์ฐพ๋Š” ์ด์ง„ํƒ์ƒ‰
    """
    result = right + 1
    
    while left <= right:
        mid = (left + right) // 2
        
        if check_function(mid):
            result = mid
            right = mid - 1
        else:
            left = mid + 1
    
    return result

# ์˜ˆ์‹œ: ๋‚˜๋ฌด ์ž๋ฅด๊ธฐ ๋ฌธ์ œ
def can_cut_wood(trees, height, target):
    """๋†’์ด height๋กœ ์ž˜๋ž์„ ๋•Œ target ์ด์ƒ์˜ ๋‚˜๋ฌด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š”์ง€"""
    total = sum(max(0, tree - height) for tree in trees)
    return total >= target

trees = [20, 15, 10, 17]
target = 7
max_height = parametric_search(
    lambda h: can_cut_wood(trees, h, target), 
    0, max(trees)
)

๐Ÿšจ ์ •๋ ฌ/์ด์ง„ํƒ์ƒ‰ ์ฃผ์š” ํ•จ์ •

  • ์ด์ง„ํƒ์ƒ‰ ์ „ ๋ฐ˜๋“œ์‹œ ์ •๋ ฌ ํ•„์š”
  • left <= right vs left < right ์กฐ๊ฑด ์ฐจ์ด
  • ๋ฌดํ•œ๋ฃจํ”„ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ mid ๊ณ„์‚ฐ ์ฃผ์˜
  • overflow ๋ฐฉ์ง€: mid = left + (right - left) // 2

๐Ÿ‘ฅ 3. ํˆฌ ํฌ์ธํ„ฐ, ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ

ํˆฌ ํฌ์ธํ„ฐ ๊ธฐ๋ฒ•

๊ธฐ๋ณธ ํˆฌ ํฌ์ธํ„ฐ

def two_sum_sorted(arr, target):
    """์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํ•ฉ์ด target์ธ ๋‘ ์ˆ˜ ์ฐพ๊ธฐ"""
    left, right = 0, len(arr) - 1
    
    while left < right:
        current_sum = arr[left] + arr[right]
        
        if current_sum == target:
            return [left, right]
        elif current_sum < target:
            left += 1
        else:
            right -= 1
    
    return [-1, -1]  # ์ฐพ์ง€ ๋ชปํ•จ

์—ฐ์† ๋ถ€๋ถ„๋ฐฐ์—ด์˜ ํ•ฉ

def subarray_sum(arr, target):
    """ํ•ฉ์ด target์ธ ์—ฐ์† ๋ถ€๋ถ„๋ฐฐ์—ด์˜ ๊ฐœ์ˆ˜"""
    left = 0
    current_sum = 0
    count = 0
    
    for right in range(len(arr)):
        current_sum += arr[right]
        
        # ํ•ฉ์ด target๋ณด๋‹ค ํด ๋•Œ left ํฌ์ธํ„ฐ ์ด๋™
        while current_sum > target and left <= right:
            current_sum -= arr[left]
            left += 1
        
        if current_sum == target:
            count += 1
    
    return count

์„œ๋กœ ๋‹ค๋ฅธ ๋ฌธ์ž์˜ ์ตœ์žฅ ๋ถ€๋ถ„๋ฌธ์ž์—ด

def longest_unique_substring(s):
    """์„œ๋กœ ๋‹ค๋ฅธ ๋ฌธ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ ์ตœ์žฅ ๋ถ€๋ถ„๋ฌธ์ž์—ด์˜ ๊ธธ์ด"""
    left = 0
    max_length = 0
    char_set = set()
    
    for right in range(len(s)):
        # ์ค‘๋ณต ๋ฌธ์ž๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ left ์ด๋™
        while s[right] in char_set:
            char_set.remove(s[left])
            left += 1
        
        char_set.add(s[right])
        max_length = max(max_length, right - left + 1)
    
    return max_length

์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ

๊ณ ์ • ํฌ๊ธฐ ์œˆ๋„์šฐ

def max_sum_subarray(arr, k):
    """ํฌ๊ธฐ๊ฐ€ k์ธ ๋ถ€๋ถ„๋ฐฐ์—ด์˜ ์ตœ๋Œ€ ํ•ฉ"""
    if len(arr) < k:
        return -1
    
    # ์ฒซ ๋ฒˆ์งธ ์œˆ๋„์šฐ์˜ ํ•ฉ
    window_sum = sum(arr[:k])
    max_sum = window_sum
    
    # ์œˆ๋„์šฐ๋ฅผ ์Šฌ๋ผ์ด๋”ฉํ•˜๋ฉด์„œ ํ•ฉ ๊ณ„์‚ฐ
    for i in range(k, len(arr)):
        window_sum = window_sum - arr[i - k] + arr[i]
        max_sum = max(max_sum, window_sum)
    
    return max_sum

๊ฐ€๋ณ€ ํฌ๊ธฐ ์œˆ๋„์šฐ

def min_window_sum(arr, target):
    """ํ•ฉ์ด target ์ด์ƒ์ธ ์ตœ์†Œ ๊ธธ์ด ๋ถ€๋ถ„๋ฐฐ์—ด"""
    left = 0
    min_length = float('inf')
    current_sum = 0
    
    for right in range(len(arr)):
        current_sum += arr[right]
        
        # ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋™์•ˆ ์œˆ๋„์šฐ ํฌ๊ธฐ ์ค„์ด๊ธฐ
        while current_sum >= target:
            min_length = min(min_length, right - left + 1)
            current_sum -= arr[left]
            left += 1
    
    return min_length if min_length != float('inf') else 0

๋ฌธ์ž์—ด์—์„œ ํŒจํ„ด ๋งค์นญ

def find_anagrams(s, p):
    """๋ฌธ์ž์—ด s์—์„œ p์˜ anagram์ธ ๋ถ€๋ถ„๋ฌธ์ž์—ด์˜ ์‹œ์ž‘ ์ธ๋ฑ์Šค๋“ค"""
    from collections import Counter
    
    if len(p) > len(s):
        return []
    
    p_count = Counter(p)
    window_count = Counter()
    result = []
    
    for i in range(len(s)):
        # ์œˆ๋„์šฐ์— ๋ฌธ์ž ์ถ”๊ฐ€
        window_count[s[i]] += 1
        
        # ์œˆ๋„์šฐ ํฌ๊ธฐ๊ฐ€ p์˜ ๊ธธ์ด์™€ ๊ฐ™์•„์ง€๋ฉด
        if i >= len(p) - 1:
            if window_count == p_count:
                result.append(i - len(p) + 1)
            
            # ์œˆ๋„์šฐ์—์„œ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž ์ œ๊ฑฐ
            left_char = s[i - len(p) + 1]
            window_count[left_char] -= 1
            if window_count[left_char] == 0:
                del window_count[left_char]
    
    return result

๐Ÿšจ ํˆฌ ํฌ์ธํ„ฐ/์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ ์ฃผ์š” ํ•จ์ •

  • ํฌ์ธํ„ฐ ์ด๋™ ์กฐ๊ฑด์„ ๋ช…ํ™•ํžˆ ์ •์˜
  • ์œˆ๋„์šฐ ํฌ๊ธฐ ์กฐ์ ˆ ์‹œ ๊ฒฝ๊ณ„ ์กฐ๊ฑด ์ฃผ์˜
  • Counter๋‚˜ ๋”•์…”๋„ˆ๋ฆฌ ์‚ฌ์šฉ ์‹œ 0์ด ๋˜๋Š” ํ‚ค ์ฒ˜๋ฆฌ

๐Ÿƒ 4. ๊ทธ๋ฆฌ๋”” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด

๊ธฐ๋ณธ ๊ทธ๋ฆฌ๋”” ํŒจํ„ด

ํ™œ๋™ ์„ ํƒ ๋ฌธ์ œ

def activity_selection(activities):
    """๋๋‚˜๋Š” ์‹œ๊ฐ„์ด ๋น ๋ฅธ ์ˆœ์œผ๋กœ ์ตœ๋Œ€ํ•œ ๋งŽ์€ ํ™œ๋™ ์„ ํƒ"""
    # (์‹œ์ž‘์‹œ๊ฐ„, ๋์‹œ๊ฐ„) ํŠœํ”Œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋์‹œ๊ฐ„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
    activities.sort(key=lambda x: x[1])
    
    selected = [activities[0]]
    last_end_time = activities[0][1]
    
    for start, end in activities[1:]:
        if start >= last_end_time:  # ๊ฒน์น˜์ง€ ์•Š์œผ๋ฉด ์„ ํƒ
            selected.append((start, end))
            last_end_time = end
    
    return selected

# ์‚ฌ์šฉ ์˜ˆ์‹œ
activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11)]
result = activity_selection(activities)

๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ

def make_change(amount, coins):
    """๊ฐ€์žฅ ์ ์€ ๊ฐœ์ˆ˜์˜ ๋™์ „์œผ๋กœ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋งŒ๋“ค๊ธฐ (๊ทธ๋ฆฌ๋”” ์กฐ๊ฑด ๋งŒ์กฑ ์‹œ)"""
    coins.sort(reverse=True)  # ํฐ ๋™์ „๋ถ€ํ„ฐ
    
    result = []
    for coin in coins:
        count = amount // coin
        if count > 0:
            result.extend([coin] * count)
            amount %= coin
        
        if amount == 0:
            break
    
    return result if amount == 0 else []  # ๋งŒ๋“ค ์ˆ˜ ์—†์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ

# ์‚ฌ์šฉ ์˜ˆ์‹œ
coins = [500, 100, 50, 10]
change = make_change(1260, coins)

์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ (ํฌ๋ฃจ์Šค์นผ)

def find_parent(parent, x):
    """Union-Find์˜ find ์—ฐ์‚ฐ"""
    if parent[x] != x:
        parent[x] = find_parent(parent, parent[x])
    return parent[x]

def union_parent(parent, rank, a, b):
    """Union-Find์˜ union ์—ฐ์‚ฐ"""
    a = find_parent(parent, a)
    b = find_parent(parent, b)
    
    if rank[a] < rank[b]:
        parent[a] = b
    elif rank[a] > rank[b]:
        parent[b] = a
    else:
        parent[b] = a
        rank[a] += 1

def kruskal(n, edges):
    """ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ"""
    # ๊ฐ„์„ ์„ ๋น„์šฉ ์ˆœ์œผ๋กœ ์ •๋ ฌ
    edges.sort(key=lambda x: x[2])
    
    parent = list(range(n))
    rank = [0] * n
    mst = []
    total_cost = 0
    
    for a, b, cost in edges:
        if find_parent(parent, a) != find_parent(parent, b):
            union_parent(parent, rank, a, b)
            mst.append((a, b, cost))
            total_cost += cost
    
    return mst, total_cost

๊ทธ๋ฆฌ๋”” ์„ ํƒ์˜ ์ •๋‹น์„ฑ ์ฆ๋ช… ํŒจํ„ด

ํšŒ์˜์‹ค ๋ฐฐ์ •

def meeting_rooms(meetings):
    """์ตœ์†Œํ•œ์˜ ํšŒ์˜์‹ค๋กœ ๋ชจ๋“  ํšŒ์˜ ๋ฐฐ์ •"""
    import heapq
    
    if not meetings:
        return 0
    
    # ์‹œ์ž‘์‹œ๊ฐ„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
    meetings.sort(key=lambda x: x[0])
    
    # ๊ฐ ํšŒ์˜์‹ค์˜ ๋๋‚˜๋Š” ์‹œ๊ฐ„์„ ์ €์žฅํ•˜๋Š” ์ตœ์†Œ ํž™
    heap = []
    
    for start, end in meetings:
        # ๊ฐ€์žฅ ๋นจ๋ฆฌ ๋๋‚˜๋Š” ํšŒ์˜์‹ค์ด ํ˜„์žฌ ํšŒ์˜ ์‹œ์ž‘ ์ „์— ๋๋‚˜๋ฉด
        if heap and heap[0] <= start:
            heapq.heappop(heap)
        
        heapq.heappush(heap, end)
    
    return len(heap)  # ํ•„์š”ํ•œ ํšŒ์˜์‹ค ๊ฐœ์ˆ˜

๐Ÿšจ ๊ทธ๋ฆฌ๋”” ์ฃผ์š” ํ•จ์ •

  • ๊ทธ๋ฆฌ๋”” ์„ ํƒ์ด ํ•ญ์ƒ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š์Œ
  • ๋ฐ˜๋ก€๋ฅผ ์ฐพ์•„ ๊ทธ๋ฆฌ๋”” ์กฐ๊ฑด ํ™•์ธ ํ•„์š”
  • ์ •๋ ฌ ๊ธฐ์ค€์„ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ ํƒ

๐Ÿงฎ 5. ๋™์ ๊ณ„ํš๋ฒ•(DP) ๊ธฐ๋ณธ ํŒจํ„ด

๊ธฐ๋ณธ DP ํŒจํ„ด

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด

# Top-down (๋ฉ”๋ชจ์ด์ œ์ด์…˜)
def fibonacci_memo(n, memo={}):
    if n in memo:
        return memo[n]
    
    if n <= 1:
        return n
    
    memo[n] = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo)
    return memo[n]

# Bottom-up (ํ…Œ์ด๋ธ” ๋ฐฉ์‹)
def fibonacci_dp(n):
    if n <= 1:
        return n
    
    dp = [0] * (n + 1)
    dp[1] = 1
    
    for i in range(2, n + 1):
        dp[i] = dp[i-1] + dp[i-2]
    
    return dp[n]

# ๊ณต๊ฐ„ ์ตœ์ ํ™”
def fibonacci_optimized(n):
    if n <= 1:
        return n
    
    prev2, prev1 = 0, 1
    for i in range(2, n + 1):
        current = prev1 + prev2
        prev2, prev1 = prev1, current
    
    return prev1

0-1 ๋ฐฐ๋‚ญ ๋ฌธ์ œ

def knapsack_01(weights, values, capacity):
    """0-1 ๋ฐฐ๋‚ญ ๋ฌธ์ œ"""
    n = len(weights)
    # dp[i][w] = i๋ฒˆ์งธ ๋ฌผ๊ฑด๊นŒ์ง€ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ๋ฌด๊ฒŒ w ์ดํ•˜๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๊ฐ€์น˜
    dp = [[0] * (capacity + 1) for _ in range(n + 1)]
    
    for i in range(1, n + 1):
        for w in range(1, capacity + 1):
            # i๋ฒˆ์งธ ๋ฌผ๊ฑด์„ ๋„ฃ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
            dp[i][w] = dp[i-1][w]
            
            # i๋ฒˆ์งธ ๋ฌผ๊ฑด์„ ๋„ฃ๋Š” ๊ฒฝ์šฐ (๋ฌด๊ฒŒ๊ฐ€ ํ—ˆ์šฉ๋˜๋ฉด)
            if weights[i-1] <= w:
                dp[i][w] = max(dp[i][w], 
                              dp[i-1][w-weights[i-1]] + values[i-1])
    
    return dp[n][capacity]

# ๊ณต๊ฐ„ ์ตœ์ ํ™” ๋ฒ„์ „
def knapsack_01_optimized(weights, values, capacity):
    dp = [0] * (capacity + 1)
    
    for i in range(len(weights)):
        # ๋’ค์—์„œ๋ถ€ํ„ฐ ๊ฐฑ์‹  (์ค‘๋ณต ์‚ฌ์šฉ ๋ฐฉ์ง€)
        for w in range(capacity, weights[i] - 1, -1):
            dp[w] = max(dp[w], dp[w - weights[i]] + values[i])
    
    return dp[capacity]

์ตœ์žฅ ์ฆ๊ฐ€ ๋ถ€๋ถ„ ์ˆ˜์—ด (LIS)

def lis_dp(arr):
    """O(nยฒ) ๋™์ ๊ณ„ํš๋ฒ•"""
    n = len(arr)
    dp = [1] * n  # dp[i] = i๋ฒˆ์งธ ์›์†Œ๋ฅผ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๋Š” LIS ๊ธธ์ด
    
    for i in range(1, n):
        for j in range(i):
            if arr[j] < arr[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    
    return max(dp)

def lis_binary_search(arr):
    """O(n log n) ์ด์ง„ํƒ์ƒ‰"""
    import bisect
    
    tails = []  # tails[i] = ๊ธธ์ด i+1์ธ ์ฆ๊ฐ€์ˆ˜์—ด์˜ ๋งˆ์ง€๋ง‰ ์›์†Œ ์ค‘ ์ตœ์†Ÿ๊ฐ’
    
    for num in arr:
        pos = bisect.bisect_left(tails, num)
        if pos == len(tails):
            tails.append(num)
        else:
            tails[pos] = num
    
    return len(tails)

ํŽธ์ง‘ ๊ฑฐ๋ฆฌ (Edit Distance)

def edit_distance(str1, str2):
    """๋‘ ๋ฌธ์ž์—ด ๊ฐ„์˜ ํŽธ์ง‘ ๊ฑฐ๋ฆฌ (์‚ฝ์ž…, ์‚ญ์ œ, ๊ต์ฒด)"""
    m, n = len(str1), len(str2)
    
    # dp[i][j] = str1[:i]๋ฅผ str2[:j]๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ตœ์†Œ ์—ฐ์‚ฐ ์ˆ˜
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    
    # ์ดˆ๊ธฐํ™”: ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜
    for i in range(m + 1):
        dp[i][0] = i  # ๋ชจ๋‘ ์‚ญ์ œ
    for j in range(n + 1):
        dp[0][j] = j  # ๋ชจ๋‘ ์‚ฝ์ž…
    
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i-1] == str2[j-1]:
                dp[i][j] = dp[i-1][j-1]  # ๋ฌธ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด ๊ทธ๋Œ€๋กœ
            else:
                dp[i][j] = 1 + min(
                    dp[i-1][j],    # ์‚ญ์ œ
                    dp[i][j-1],    # ์‚ฝ์ž…
                    dp[i-1][j-1]   # ๊ต์ฒด
                )
    
    return dp[m][n]

DP ์ƒํƒœ ์„ค๊ณ„ ํŒจํ„ด

๊ตฌ๊ฐ„ DP

def matrix_chain_multiplication(matrices):
    """ํ–‰๋ ฌ ์—ฐ์‡„ ๊ณฑ์…ˆ์˜ ์ตœ์†Œ ๊ณฑ์…ˆ ํšŸ์ˆ˜"""
    n = len(matrices)
    # dp[i][j] = i๋ฒˆ์งธ๋ถ€ํ„ฐ j๋ฒˆ์งธ ํ–‰๋ ฌ๊นŒ์ง€ ๊ณฑํ•˜๋Š” ์ตœ์†Œ ๋น„์šฉ
    dp = [[0] * n for _ in range(n)]
    
    # ๊ตฌ๊ฐ„ ๊ธธ์ด๋ฅผ ๋Š˜๋ ค๊ฐ€๋ฉฐ ๊ณ„์‚ฐ
    for length in range(2, n + 1):  # ๊ตฌ๊ฐ„ ๊ธธ์ด
        for i in range(n - length + 1):
            j = i + length - 1
            dp[i][j] = float('inf')
            
            # k๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ถ„ํ• 
            for k in range(i, j):
                cost = (dp[i][k] + dp[k+1][j] + 
                       matrices[i][0] * matrices[k][1] * matrices[j][1])
                dp[i][j] = min(dp[i][j], cost)
    
    return dp[0][n-1]

๋น„ํŠธ๋งˆ์Šคํฌ DP

def traveling_salesman(dist):
    """์™ธํŒ์› ๋ฌธ์ œ (TSP)"""
    n = len(dist)
    # dp[mask][i] = mask์— ํ‘œ์‹œ๋œ ๋„์‹œ๋“ค์„ ๋ฐฉ๋ฌธํ•˜๊ณ  i์—์„œ ๋๋‚˜๋Š” ์ตœ์†Œ ๋น„์šฉ
    dp = [[float('inf')] * n for _ in range(1 << n)]
    
    # ์‹œ์ž‘์ (0๋ฒˆ ๋„์‹œ)์—์„œ ์ถœ๋ฐœ
    dp[1][0] = 0
    
    for mask in range(1 << n):
        for i in range(n):
            if not (mask & (1 << i)):  # i๋ฒˆ ๋„์‹œ๋ฅผ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์•˜์œผ๋ฉด
                continue
            
            for j in range(n):
                if i == j or not (mask & (1 << j)):
                    continue
                
                # j์—์„œ i๋กœ ๊ฐ€๋Š” ๊ฒฝ์šฐ
                prev_mask = mask ^ (1 << i)
                dp[mask][i] = min(dp[mask][i], 
                                 dp[prev_mask][j] + dist[j][i])
    
    # ๋ชจ๋“  ๋„์‹œ๋ฅผ ๋ฐฉ๋ฌธํ•˜๊ณ  ์‹œ์ž‘์ ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ์ตœ์†Œ ๋น„์šฉ
    result = float('inf')
    final_mask = (1 << n) - 1
    for i in range(1, n):
        result = min(result, dp[final_mask][i] + dist[i][0])
    
    return result

๐Ÿšจ DP ์ฃผ์š” ํ•จ์ •

  • ์ƒํƒœ ์ •์˜๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ตฌํ˜„ ์–ด๋ ค์›€
  • ๋ฉ”๋ชจ์ด์ œ์ด์…˜์—์„œ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ • ์ฃผ์˜
  • ์ˆœ์„œ์— ๋”ฐ๋ฅธ ์ค‘๋ณต ๊ณ„์‚ฐ ๋ฐฉ์ง€
  • ๊ณต๊ฐ„ ๋ณต์žก๋„ ์ตœ์ ํ™” ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€ํ† 

๐Ÿ”ค 6. ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•

ํŒจํ„ด ๋งค์นญ

KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜

def build_failure_function(pattern):
    """KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹คํŒจ ํ•จ์ˆ˜ ๊ตฌ์ถ•"""
    m = len(pattern)
    failure = [0] * m
    j = 0
    
    for i in range(1, m):
        while j > 0 and pattern[i] != pattern[j]:
            j = failure[j - 1]
        
        if pattern[i] == pattern[j]:
            j += 1
            failure[i] = j
    
    return failure

def kmp_search(text, pattern):
    """KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ํŒจํ„ด ๊ฒ€์ƒ‰"""
    n, m = len(text), len(pattern)
    if m == 0:
        return []
    
    failure = build_failure_function(pattern)
    matches = []
    j = 0
    
    for i in range(n):
        while j > 0 and text[i] != pattern[j]:
            j = failure[j - 1]
        
        if text[i] == pattern[j]:
            j += 1
        
        if j == m:
            matches.append(i - m + 1)
            j = failure[j - 1]
    
    return matches

๋ผ๋นˆ-์นดํ”„ ์•Œ๊ณ ๋ฆฌ์ฆ˜

def rabin_karp_search(text, pattern):
    """๋ผ๋นˆ-์นดํ”„ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (๋กค๋ง ํ•ด์‹œ)"""
    n, m = len(text), len(pattern)
    if m > n:
        return []
    
    base = 256
    mod = 10**9 + 7
    
    # ํŒจํ„ด์˜ ํ•ด์‹œ๊ฐ’ ๊ณ„์‚ฐ
    pattern_hash = 0
    for char in pattern:
        pattern_hash = (pattern_hash * base + ord(char)) % mod
    
    # base^(m-1) % mod ๊ณ„์‚ฐ
    h = 1
    for _ in range(m - 1):
        h = (h * base) % mod
    
    # ์ฒซ ๋ฒˆ์งธ ์œˆ๋„์šฐ์˜ ํ•ด์‹œ๊ฐ’
    window_hash = 0
    for i in range(m):
        window_hash = (window_hash * base + ord(text[i])) % mod
    
    matches = []
    for i in range(n - m + 1):
        # ํ•ด์‹œ๊ฐ’์ด ๊ฐ™์œผ๋ฉด ์‹ค์ œ ๋ฌธ์ž์—ด ๋น„๊ต
        if window_hash == pattern_hash:
            if text[i:i+m] == pattern:
                matches.append(i)
        
        # ๋‹ค์Œ ์œˆ๋„์šฐ์˜ ํ•ด์‹œ๊ฐ’ ๊ณ„์‚ฐ (๋กค๋ง)
        if i < n - m:
            window_hash = (window_hash - ord(text[i]) * h) % mod
            window_hash = (window_hash * base + ord(text[i + m])) % mod
            window_hash = (window_hash + mod) % mod  # ์Œ์ˆ˜ ๋ฐฉ์ง€
    
    return matches

๋ฌธ์ž์—ด ๋ณ€ํ™˜๊ณผ ์ฒ˜๋ฆฌ

ํšŒ๋ฌธ ๊ฒ€์‚ฌ์™€ ๊ด€๋ จ ์•Œ๊ณ ๋ฆฌ์ฆ˜

def is_palindrome(s):
    """๊ธฐ๋ณธ ํšŒ๋ฌธ ๊ฒ€์‚ฌ"""
    left, right = 0, len(s) - 1
    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1
    return True

def longest_palindrome_center_expand(s):
    """์ค‘์‹ฌ ํ™•์žฅ์œผ๋กœ ์ตœ์žฅ ํšŒ๋ฌธ ์ฐพ๊ธฐ"""
    def expand_around_center(left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return right - left - 1
    
    start = end = 0
    for i in range(len(s)):
        # ํ™€์ˆ˜ ๊ธธ์ด ํšŒ๋ฌธ
        len1 = expand_around_center(i, i)
        # ์ง์ˆ˜ ๊ธธ์ด ํšŒ๋ฌธ
        len2 = expand_around_center(i, i + 1)
        
        max_len = max(len1, len2)
        if max_len > end - start:
            start = i - (max_len - 1) // 2
            end = i + max_len // 2
    
    return s[start:end + 1]

def manacher_algorithm(s):
    """๋งค๋‚ด์ฒ˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (O(n) ํšŒ๋ฌธ ๊ฒ€์‚ฌ)"""
    # ๋ฌธ์ž ์‚ฌ์ด์— ํŠน๋ณ„ ๋ฌธ์ž ์‚ฝ์ž…
    processed = '#'.join('^{}$'.format(s))
    n = len(processed)
    
    # ๊ฐ ์œ„์น˜์—์„œ์˜ ํšŒ๋ฌธ ๋ฐ˜์ง€๋ฆ„
    radius = [0] * n
    center = right = 0
    
    for i in range(1, n - 1):
        # ์ด์ „์— ๊ณ„์‚ฐ๋œ ์ •๋ณด ํ™œ์šฉ
        if i < right:
            radius[i] = min(right - i, radius[2 * center - i])
        
        # ์ค‘์‹ฌ ํ™•์žฅ
        while processed[i + radius[i] + 1] == processed[i - radius[i] - 1]:
            radius[i] += 1
        
        # ์˜ค๋ฅธ์ชฝ ๊ฒฝ๊ณ„ ๊ฐฑ์‹ 
        if i + radius[i] > right:
            center, right = i, i + radius[i]
    
    # ์ตœ์žฅ ํšŒ๋ฌธ ์ฐพ๊ธฐ
    max_len = max(radius)
    center_index = radius.index(max_len)
    start = (center_index - max_len) // 2
    
    return s[start:start + max_len]

์ ‘๋ฏธ์‚ฌ ๋ฐฐ์—ด๊ณผ LCP

def suffix_array_naive(s):
    """์ ‘๋ฏธ์‚ฌ ๋ฐฐ์—ด (๋‹จ์ˆœ ๊ตฌํ˜„)"""
    suffixes = [(s[i:], i) for i in range(len(s))]
    suffixes.sort()
    return [suffix[1] for suffix in suffixes]

def lcp_array(s, suffix_arr):
    """์ตœ์žฅ ๊ณตํ†ต ์ ‘๋‘์‚ฌ ๋ฐฐ์—ด"""
    n = len(s)
    rank = [0] * n
    lcp = [0] * (n - 1)
    
    # ๊ฐ ์ ‘๋ฏธ์‚ฌ์˜ ์ˆœ์œ„ ๊ณ„์‚ฐ
    for i in range(n):
        rank[suffix_arr[i]] = i
    
    h = 0
    for i in range(n):
        if rank[i] > 0:
            j = suffix_arr[rank[i] - 1]
            while (i + h < n and j + h < n and 
                   s[i + h] == s[j + h]):
                h += 1
            lcp[rank[i] - 1] = h
            if h > 0:
                h -= 1
    
    return lcp

์ •๊ทœํ‘œํ˜„์‹ ํŒจํ„ด

import re

# ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ •๊ทœํ‘œํ˜„์‹ ํŒจํ„ด๋“ค
patterns = {
    'email': r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
    'phone': r'^\d{3}-\d{3,4}-\d{4}$',
    'number': r'^-?\d+(\.\d+)?$',
    'korean': r'[๊ฐ€-ํžฃ]+',
    'english': r'[a-zA-Z]+',
    'alphanumeric': r'^[a-zA-Z0-9]+$'
}

def validate_input(text, pattern_name):
    """์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ"""
    pattern = patterns.get(pattern_name)
    if pattern:
        return bool(re.match(pattern, text))
    return False

# ๋ฌธ์ž์—ด์—์„œ ๋ชจ๋“  ์ˆซ์ž ์ถ”์ถœ
def extract_numbers(text):
    return re.findall(r'-?\d+\.?\d*', text)

# ํŠน์ • ํŒจํ„ด์œผ๋กœ ๋ฌธ์ž์—ด ๋ถ„ํ• 
def smart_split(text, delimiter_pattern=r'[,;\s]+'):
    return re.split(delimiter_pattern, text.strip())

๐Ÿšจ ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ ์ฃผ์š” ํ•จ์ •

  • ์œ ๋‹ˆ์ฝ”๋“œ ์ฒ˜๋ฆฌ ์‹œ ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ
  • ์ •๊ทœํ‘œํ˜„์‹์˜ ์„ฑ๋Šฅ ์ด์Šˆ (๋ฐฑํŠธ๋ž˜ํ‚น)
  • ๋ฌธ์ž์—ด ๋ถˆ๋ณ€์„ฑ์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜
  • KMP/๋ผ๋นˆ-์นดํ”„์—์„œ ๋ชจ๋“ˆ๋กœ ์—ฐ์‚ฐ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ

๐Ÿ“ 2๋‹จ๊ณ„ ํ•ต์‹ฌ ์š”์•ฝ

ํ•„์ˆ˜ ์•”๊ธฐ ํ…œํ”Œ๋ฆฟ

  1. DFS/BFS: ์žฌ๊ท€/์Šคํƒ/ํ๋ฅผ ์ด์šฉํ•œ ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰
  2. ์ด์ง„ํƒ์ƒ‰: lower_bound, upper_bound, ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ์ƒ‰
  3. ํˆฌ ํฌ์ธํ„ฐ: ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ์กฐ๊ฑด ๋งŒ์กฑํ•˜๋Š” ์Œ ์ฐพ๊ธฐ
  4. ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ: ๊ณ ์ •/๊ฐ€๋ณ€ ํฌ๊ธฐ ๋ถ€๋ถ„๋ฐฐ์—ด ๋ฌธ์ œ
  5. ๊ทธ๋ฆฌ๋””: ํ™œ๋™ ์„ ํƒ, ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ
  6. DP: 0-1๋ฐฐ๋‚ญ, LIS, ํŽธ์ง‘๊ฑฐ๋ฆฌ

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ ๊ฐ€์ด๋“œ

  • ์™„์ „ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•œ๊ฐ€? โ†’ DFS/BFS
  • ์ •๋ ฌ๋œ ์ƒํƒœ์—์„œ ํŠน์ • ๊ฐ’ ์ฐพ๊ธฐ โ†’ ์ด์ง„ํƒ์ƒ‰
  • ์—ฐ์†๋œ ๋ถ€๋ถ„์—์„œ ์กฐ๊ฑด ๋งŒ์กฑ โ†’ ํˆฌ ํฌ์ธํ„ฐ/์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ
  • ๋งค ์ˆœ๊ฐ„ ์ตœ์„ ์˜ ์„ ํƒ โ†’ ๊ทธ๋ฆฌ๋””
  • ์ž‘์€ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๋กœ ํฐ ๋ฌธ์ œ ํ•ด๊ฒฐ โ†’ DP
  • ํŒจํ„ด ๊ฒ€์ƒ‰/๋ฌธ์ž์—ด ๋ณ€ํ™˜ โ†’ KMP/๋ผ๋นˆ-์นดํ”„