///
Search
📠

알고리즘

태그
CS
Major
Baekjoon
LarryKwon
Table
Search
유형
이름

Hash Function

쓰이는 곳
De-Duplication
the 2-sum problem
성능
alpha에 따라 다름. 이걸 적절히 해줘야함.resizing 가능. 좋은 hash function 쓰면 됨.
modular일 때는 소수 근처로 하는 거 추천

Bloom Filter

False Negative는 없음
실제로는 있는데 없다고 하는 경우 없음.
array of n bits → insert & look up.
k개 hash function 써서 적당한 비트에 1로 표시하기
lookup 시, 모든 k hash function에 대해서 1인지 체크하기
하나의 array bit가 1로 체크 안 될 확률 → (1-1/n)^k|S|
1로 될 확률 → 1 - ~~
적당히 바꾸기, k = ln2 * b

BST

Operation
Insert, Delete
Delete가 문제임
leaf → 그냥 삭제
middle →child 하나: 그냥 삭제 후 대체
middle → child 둘: predecessor 찾기(자기랑 바꾸기)
Rank
size = # of tree nodes in subtree rooted at x
left, right가 있는데, i에 대해서 왼쪽 오른쪽을 각각 비교해봄
왼쪽이랑 비교했는데 i가 크면 오른쪽으로 이 때 i - a - 1로 가기. (i - 왼쪽 갯수 - 루트 갯수)
왼쪽이랑 비교했는데 i가 작으면 왼쪽으로 i로 가기
i-1이랑 왼쪽이랑 같으면 그냥 지금꺼 반환

레드-블랙 트리

항상 정렬 맞추기
모든 노드는 블랙/레드
루트는 블랙
블랙 다음에 블랙은 되지만, 레드가 연속으로 나올 순 없음
모든 root-NULL에는 블랙 개수가 같아야함.
따라서 레드는 갯수에는 포함이 안 되지만 연속으로는 못 쓰기 때문에 가장 미니멈한 갯수에 대해서 뻗어나가는 제한이 생길 수 밖에 없음.
root-NULL 패스가 k 노드를 가지고 있다 → 미니멈하게 2^k -1개 노드임
n ≥ 2^k - 1인데, k는 그래서 log(n+1)보다 작음. 이 말은 최대 log(n+1)의 노드가 있다는 뜻임. 따라서 최대 길이는 이거 2배
로테이션이 있음
Insertion
coloring red
연속된 red이다.
y는 블랙 parent w가 있음
이 과정에서 다른 자식z을 봐야함
블랙
rorate and recolor를 해야함.
레드
y,z는 블랙으로 w는 레드로 만들기

BFS

→ queue 사용
→ layer 별 접근
→ O(m+n)

DFS

→ stack 사용
→ O(m+n)

Topological sort

directed graph에서 순서 메기기
sink node부터 거꾸로 메기기
DFS를 해서 set f(s) = current_label
current_label 1씩 줄여가기

SSC and Kosaraju

모든 v→v가 성립되면 strongly connected
kosaraju
ssc를 추상화해서 metapath로 만들 시, 우리는 sink 노드부터 공략해야햠.
sink 노드부터 넘버링이 잘 되어있어야함.
1.
2-pass임
a.
G_rev에 대해서 DFS를 돔. 이 때, 끝나는 시간에 맞춰서 넘버링을 진행해야함. 뒤에서부터 1,2 이렇게 매긴다는 듯
b.
이 번호를 자기 번호로 매김
c.
원래 G에서 그 번호가 큰 순서대로 DFS를 돔
두 번 DFS → O(m+n)임.
proof
→ adjacent SSC에 대해서 C1, C2
G_rev에 대해서 생각했을 때 첫 방문이 어디로 되어도 C1 → C2이면 C2의 finishing time이 항상 더 큼.
C2→ C1일 때, C1부터 떨어지면, 확실히 C1의 모든 값이 C2보다 작음
C2→C1일 때 C1부터 떨어지면, 어떻게든 C2에서 일단 시작을 하니까 C1의 모든 값보다 큰 거 무조건 하나는 있음

Dijkstra

source가 주어질 때, 모든 노드에 대한 최단 경로를 저장 + 복원할 수 있음
발견한 노드와 아닌 노드를 X랑 V-X로 놓음
모든 노드를 돌면서
그 둘 사이를 건너는 엣지들에 대해서 minimize할 수 있는걸 고름
proof
induction + 모순
특정 시점에 A[v] = L(v)로 잘 저장이 되었다고 할 때,
그 다음 노드 w를 고를 거임.
근데 우리는 이 때 최소 엣지를 pick할 예정임.
s→w*에 대해서 일반화를 해보자면 s → v* → w*는 s → y → z → w*으로 표현할 수 있는데
이 때 길이는 A[y] + l_yz임. 근데 우리는 pick을 할 때 이미 s→z에 대해서 최소가 되는 걸 뽑기 때문에 z→w*가 0보다 무조건 크니까 우리가 뽑은게 최소임. 다른 것들은 이것보다 다 같거나 큼.
O(nm)인데 heap 쓰면 더 빠름
heap에서 key는 score가 되도록 설정함.
value는 vertex임.
매번 heap에서 뽑을 때, score 기준으로 뽑혀 나오게끔. 나오고 나면 업데이트 해줘야함.
key[v] = min{key[v], A[w]+I_wv}가 되도록 log n
생각해보면 삭제/삽입 2번이고 각각 log n이고, 모든 노드에 대해서 돌면서 진행하는데 이 때 간선을 무조건 한 번만 건들기 때문에 O(nlogn + 2m log n) ⇒ O(mlogn)임

Dynamic Programming

부분 문제 잘 찾는게 중요함.
부분 문제의 정답이 큰 문제의 정답이 되어야함.
어떤 요소를 induction하면서 큰 문제로 나아갈지 생각해야함.

WIS

마지막 요소에 대해서 생각하기
마지막 요소가 포함되면 그 정답은 그 set에서 전 요소, 전전 요소 뺀 상황에서도 정답임
마지막 요소가 포함이 안 되면, 그 set이 그 요소 없는 전 단계에서도 정답임.
reconstruction 어케하냐
각 단계별 요소를 보면서 판단하기
A[i-1]이거나 A[i-2] + wi거나인데
전자가 크면 그 요소가 포함이 안 됬다는 뜻이고, 후자가 크면 포함이 됬다는 뜻이니까, 각 단계에서 두 개를 비교해가며 포함할지 안 할지 right→left로 확인

냅색

weight, value에 대해서 최대화. weight에 대한 제한이 존재함.
WIS랑 똑같이 풀거임.
다만 이번엔 weight라는 요소가 추가되어서 2차원 배열로 풀거임.
모든 n에 대해, 모든 weight에 대해서
weight가 x보다 크면 A[i,x] = A[i-1,x]임
그렇지 않으면 A[i,x] = max{A[i-1,x], vi + A[i-1, x-wi]} ⇒ 이거 담았을 때랑 안 담았을 때 나눠서 생각
O(nW)

벨만 포드

single-source shortest path
negative edge에 대해서도 working 하도록 하고 싶음
DP로 풀건데, 어떻게 subproblem을 정의하냐
i-hop으로 정의
proof
induction으로 풀기
구현
A[i,v]로 구현
for i = 1 to n-1
for each v
A[i,v] = min(A[i-1,v], min(A[i-1, w] + l_wv))
O(mn)
B[i,v]를 만들어서 전단계 저장하기.
O(n) space만 있으면 됨. 전 단계만 저장
A[i-1,w] + l_wv 인 경우에 w로 저장하면 됨.

Floyd-Warshall algorithm

O(n3)로 가자
Dense인 경우 Bellman-Ford는 O(n2m)이라 O(n^4)가 됨.
optimail substracture
node 1 → n으로 갈 때
internal node를 i 노드까지로 구성할 수 있느냐.
만약에 k가 없으면 V(k-1)에서 shortest path임
K가 있으면 i-k랑 k-j가 각각 shortest path임.
A[3-D]
A[i,j,k]
i,j 는 포지션
k는 subproblem 나타냄
A[i,j,k] = min A[i,j,k-1, A[i,k,k-1] + A[k,j,k-1]이거나.

Greedy Algorithm

Scheduling
optimal한 순서가 있어. 내림차순으로 해서 1→n이 있다고 할 때
임의의 다른 optimal한 순서가 있다고 하면, inversion이 존재→ 이걸 바꾸면, 무조건 작아짐
근데 작아지는 이유가, 우리가 나열한 그 순서에 입각해서, cost benefit을 계산

MST1

MST2 - clustering

Prim
임의의 s
모든 edge에 대해서 가장 싼거 찍어서 추가
correctness
spanning Tree가 됨을 보이고
이거는 근데 연결될 때까지 하는 거라서 spanning이고.
모든 상황에서의 cut이 안 지나가게끔 할 수 있음
T*이 MST가 됨을 보이고
특히 T를 구성하는 각각이 MST의 한 요소가 됨을 보임 → cut property
만약 싸지만 MST가 아닌 게 있다고 할 때 어떻게 되는지
교환을 하면 어떠냐
교환을 할 때, 내가 추가를 해서 나오는 cycle에 대한 걸 지우면 항상 spanning함
lemma
not connected 건너는 엣지가 없다
두 번 건너면 사이클 있는거임
없으면 사이클이 없는거임
구현
O(mlogn)
일단 initialize하고 추가될 때 마다 업데이트하는 식
Dijkstra 처럼
크루스칼
그냥 모든 m에 대해서 사이클이 안 생기게끔 추가하면 됨.
correctness
cut이 고정되있을 때 크루스칼은 가장 작은 첫 번째 crossing edge 뽑는거라 그럼
근데 매번 작은 걸 뽑으니까 당연한거임..?
implementation
union-find
속한 그룹의 리더를 지정함
머지할 때, 이제 하나의 vertex에 대해서는 O(logn)만큼 일어남
mlogn + o(m) + o(nlogn)
클러스터링
그리디 알고리즘
p,q가 있는데 이미 머지 된 경우 → 이미 머지가 되었으니까 d(p,q)가 S보다 작다.