✅ 알고리즘 공부 | B트리, Trie, KMP 알고리즘, 보이어-무어 알고리즘 공부
✅ 백준 | 2869 달팽이는 올라가고 싶다, 2628 종이자르기, 1074 Z
☑️ CS:APP | 3장 안 읽은 부분 마저 읽기, CSAPP 저자 직강 유튜브 보기
https://www.youtube.com/watch?v=bqkcoSm_rCs&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=26
각 노드의 최대 자녀 노드 수 : M
각 노드의 최대 key 수 : M-1
각 노드의 최소 자녀 노드 수 : (M/2) <- 반올림
각 노드의 최소 key 수 : (M/2)-1 <- (M/2)는 반올림
맨 끝에 추가하는데 넘치면 쪼개고 가운데는 승진.
뭔가 이상해지면(키 수, 자식 수 부족해짐) 부모한테서 가져오거나 형제한테서 가져온 뒤에 합친다
왜 DB index로 B tree 계열이 사용되는가?
avg case, worst case에 대해 조회, 삽입, 삭제 모두 시간 복잡도가 O(log N)이기 때문이다.
BST는 잘못 넣으면 균형이 깨지기 때문에 스스로 균형을 맞추는 트리들이 만들어짐
AVL tree, Red-Black tree. 이것들도 시간 복잡도가 O(log N)이다.
근데 DB index에는 왜 BST 계열 말고 B tree 계열을 사용하는가?
CPU : 프로그램 코드가 실제로 실행되는 곳
Main memory : 실행 중인 프로그램들의 코드들과 코드 실행에 필요한 혹은 그 결과로 나온 데이터들이 상주하는 곳
Secondary storage : 프로그램과 데이터가 영구적으로 저장되는 곳, 실행 중인 프로그램의 데이터 일부가 임시 저장되는 곳 (DB도 여기에)
: 그게 결국 B tree 동작 방식. BST 다른 노드들 억지로 담은 다음에 그거 해석하는거 구현할 바에야 그냥 B tree 쓰는게 나음.
: hash index는 삽입/삭제/조회의 시간 복잡도가 O(1)이지만 equaility(=) 조회만 가능하고 범위 기반 검색이나 정렬에는 사용될 수 없다는 단점이 있다.
문자열에 있는 각 요소를 노드로 보고 쭉 이어주고,
여러 개 저장할 때 중복되는 요소는 생략하면
검색을 빠르게 할 수 있다.
이해 시켜준 글 : https://chanhuiseok.github.io/posts/algo-14/
패턴과 겹치는지 하나씩 확인하다가 패턴 아닌거 찾거나
그동안 앞에 얼마나 겹쳤는지 확인하고 그만큼만 앞으로 돌아감
하나도 안 겹쳤으면 그동안 찾았던 만큼 다 스킵
이 블로그 설명을 그냥 잘함 : https://chanhuiseok.github.io/posts/algo-15/
패턴에 안 들어있는건 패스
패턴에 들어있으면 뒷부분에 있는 것부터 센다.
기본적으로 KMP는 패턴에 대한 정보만 기억한다면
보이어-무어는 알파벳들에 대한 정보를 기억한다.
n = int(input())
hansu = 0
for i in range(1, n+1):
if i < 100:
hansu += 1
if i >= 100:
temp1 = int(str(i)[0]) - int(str(i)[1])
temp2 = int(str(i)[1]) - int(str(i)[2])
if temp1 == temp2:
hansu+=1
print(hansu)
간단하게 파이썬으로 짜면 이정도.
근데 너무 마음에 안 든다.
나는 뭔가 수학적으로 필요한 것만 확인하는 로직이 있을 줄 알았는데
다들 brute force로 풀었다.
저번에도 생각했던 거지만
내가 너무 최적화된 로직 아니면 마음에 안 들고 바로 떠올리지도 않는다.
문제가 여유 주면 여유만큼 풀자.
#include <iostream>
using namespace std;
int arithmetic_sequence(int num) {
int cnt = 0; // 한수 카운팅
if (num < 100) {
return num;
} else {
cnt = 99;
for (int i = 100; i <= num; i++) {
int hun = i / 100; // 백의 자릿수
int ten = (i / 10) % 10; // 십의 자릿수
int one = i % 10;
if ((hun - ten) == (ten - one)) { // 각 자릿수가 수열을 이루면
cnt++;
}
}
}
return cnt;
}
int main(int argc, char const *argv[]) {
int N;
cin >> N;
int result = arithmetic_sequence(N);
cout << result;
return 0;
}
조금 더 최적화하면 이정도긴 한데 이것도 마음에 안 듦.
print(sum([((i // 100) - (i % 100 // 10))
== ((i % 100 // 10) - (i % 10))
or i <= 99
for i in range(1, int(input())+1)]))
이 사람 좀 잘 푼듯
W, H = map(int, input().split())
N = int(input())
arr_W, arr_H = [0], [0]
for i in range(N):
WorH, line = map(int, input().split())
if WorH == 1:
arr_W.append(line)
else:
arr_H.append(line)
arr_W.append(W)
arr_H.append(H)
arr_W.sort()
arr_H.sort()
W_max, H_max = 0, 0
for i in range(len(arr_W)-1):
W_max = max(W_max,arr_W[i+1]-arr_W[i])
for i in range(len(arr_H)-1):
H_max = max(H_max,arr_H[i+1]-arr_H[i])
print(W_max * H_max)
잘 푼듯
import sys
input = sys.stdin.readline
N = int(input())
arr = [0]*10001
for _ in range(N):
n = int(input())
arr[n]+=1
for i in range(10001):
if arr[i] != 0:
for _ in range(arr[i]):
print(i)
나쁘지 않게 푼듯. 옆 동기가 딕셔너리로 풀어본다길래 아이디어 얻음.
# 사분면으로 쪼개기
N, r, c = map(int,input().split())
x, y, size = 0, 0, 2**N
cnt=0
def visitOrder(x,y,size):
global cnt
if(size == 1):
print(int(cnt))
return
half = size/2
if x+half > c:
if y+half > r:
return visitOrder(x,y,half)
else:
cnt+=size*size*(2/4)
return visitOrder(x,y+half,half)
else:
if y+half > r:
cnt+=size*size*(1/4)
return visitOrder(x+half,y,half)
else:
cnt+=size*size*(3/4)
return visitOrder(x+half,y+half,half)
visitOrder(x,y,size)
옆 동기 풀이를 많이 참고함.