일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- CSV
- 코딩테스트
- DFS
- Back tracking
- SWEA
- programmers
- gpdb
- Linked list
- Trie
- BFS
- SQL
- Priority Queue
- 코테
- aws
- 모의SW역량테스트
- Bruth Force
- 알고리듬
- spring boot
- JavaScript
- Algorithm
- 시뮬레이션
- Data Structure
- hash table
- boj
- django
- Vue.js
- Python
- 알고리즘
- GitHub
- 구현
- Today
- Total
hotamul의 개발 이야기
[Algorithm][C++] BOJ 20920: 영단어 암기는 괴로워 (Hash Table + Heap) 본문
[Algorithm][C++] BOJ 20920: 영단어 암기는 괴로워 (Hash Table + Heap)
hotamul 2021. 11. 26. 23:34url: https://www.acmicpc.net/problem/20920
20920번: 영단어 암기는 괴로워
첫째 줄에는 영어 지문에 나오는 단어의 개수 $N$과 외울 단어의 길이 기준이 되는 $M$이 공백으로 구분되어 주어진다. ($1 \leq N \leq 100\,000$, $1 \leq M \leq 10$) 둘째 줄부터 $N+1$번째 줄까지 외울 단
www.acmicpc.net
풀이 핵심
1. Hash Table을 활용해 단어가 중복되서 나온 것인지 판단한다. Heap에 우선순위 (단어가 나온 횟수, 단어 길이, 알파벳 역순)을 유지 될 수 있도록 해서 마지막에 HeapPop을 이용해 정답을 출력한다. 여기서 단어가 나온 횟수가 클수록, 단어 길이가 길수록 알파벳 역순 일 수록 부모 노드 (1에 가깝게)가 되도록 push, pop을 구성한다.
2. 단어가 중복되어 나왔다고 판단 되면 현재 이 단어의 힙 노드 위치를 리턴해주는 isExist 함수를 만든다. (힙 노드의 각각 위치를 저장 할 수있는 wordIDList를 만들어 저장한다) 힙 노드 위치로 단어에 접근해서 횟 수를 증가시키고 다시 정렬해주는 update 함수를 만든다.
void update(int wID) {
int current = heapIDList[wID];
int parent = current / 2;
heap[current]->count += 1;
while (parent > 0) {
if (comp(heap[current], heap[parent]) > 0) break;
heapIDList[heap[current]->wID] = parent;
heapIDList[heap[parent]->wID] = current;
Word* tmp = heap[current];
heap[current] = heap[parent];
heap[parent] = tmp;
current = parent;
parent = current / 2;
}
}
int isExist(const char* str, ull h) {
Node* nd = hashTable[h].next;
while (nd != 0) {
if (!mystrcmp(wordList[nd->wID].str, str)) return nd->wID;
nd = nd->next;
}
return 0;
}
전체 코드
#include <cstdio>
#define MAXN 100001
#define MAX_TABLE 100007
typedef unsigned long long ull;
int N, maxLength;
struct Word {
int wID;
char str[11];
int length;
int count;
};
Word wordList[MAXN];
Word* heap[MAXN];
int heapIDList[MAXN];
int hSize;
struct Node {
int wID;
Node* next;
};
Node nodePool[MAXN];
int pcnt;
Node hashTable[MAX_TABLE];
int mystrlen(const char* str) {
int len = 0;
while (*str++) ++len;
return len;
}
void mystrcpy(char* a, const char* b) {
while (*a++ = *b++);
}
int mystrcmp(const char* a, const char* b) {
while (*a && *a == *b) ++a, ++b;
return *a - *b;
}
ull hash(const char* str) {
ull hash = 5381;
int c;
while (c = *str++) {
hash = ((hash << 5) + hash + c) % MAX_TABLE;
}
return hash % MAX_TABLE;
}
int comp(Word* a, Word* b) {
if (a->count == b->count) {
if (a->length == b->length) {
return mystrcmp(a->str, b->str);
}
return b->length - a->length;
}
return b->count - a->count;
}
void heapPush(Word* w) {
if (hSize == MAXN - 1) return;
heap[++hSize] = w;
heapIDList[w->wID] = hSize;
int current = hSize;
int parent = hSize / 2;
while (parent > 0) {
if (comp(heap[current], heap[parent]) > 0) break;
heapIDList[heap[current]->wID] = parent;
heapIDList[heap[parent]->wID] = current;
Word* tmp = heap[current];
heap[current] = heap[parent];
heap[parent] = tmp;
current = parent;
parent = current / 2;
}
}
Word* heapPop() {
if (hSize == 0) return 0;
Word* ret = heap[1];
heap[1] = heap[hSize--];
int current = 1, leftChild = 2, rightChild = 3, child;
while (leftChild <= hSize) {
if (leftChild == hSize) child = leftChild;
else child = (comp(heap[leftChild], heap[rightChild]) > 0) ? rightChild : leftChild;
if (comp(heap[current], heap[child]) < 0) break;
heapIDList[heap[current]->wID] = child;
heapIDList[heap[child]->wID] = current;
Word* tmp = heap[current];
heap[current] = heap[child];
heap[child] = tmp;
current = child;
leftChild = current * 2;
rightChild = leftChild + 1;
}
return ret;
}
void update(int wID) {
int current = heapIDList[wID];
int parent = current / 2;
heap[current]->count += 1;
while (parent > 0) {
if (comp(heap[current], heap[parent]) > 0) break;
heapIDList[heap[current]->wID] = parent;
heapIDList[heap[parent]->wID] = current;
Word* tmp = heap[current];
heap[current] = heap[parent];
heap[parent] = tmp;
current = parent;
parent = current / 2;
}
}
int isExist(const char* str, ull h) {
Node* nd = hashTable[h].next;
while (nd != 0) {
if (!mystrcmp(wordList[nd->wID].str, str)) return nd->wID;
nd = nd->next;
}
return 0;
}
int main() {
char str[11];
scanf("%d %d", &N, &maxLength);
for (int id = 1; id <= N; id++) {
scanf("%s", str);
int length = mystrlen(str);
if (length < maxLength) continue;
ull h = hash(str);
int checkID = isExist(str, h);
if (checkID != 0) {
update(checkID);
}
else {
wordList[id].wID = id;
mystrcpy(wordList[id].str, str);
wordList[id].length = length;
wordList[id].count = 1;
heapPush(&wordList[id]);
Node* nd = &nodePool[pcnt++];
nd->wID = id;
nd->next = hashTable[h].next;
hashTable[h].next = nd;
}
}
int loop = hSize;
for (int i = 0; i < loop; i++) {
printf("%s\n", heapPop()->str);
}
return 0;
}
확실히 Priority Queue(Heap)은 구현량이 많고 update 시켜 줘야 하면 heap에 어떻게 접근 할 것인지를 잘 생각해봐야 한다. (이번 문제는 단어의 고유 ID를 이용하고 각 힙 노드의 위치를 저장하는 heapIDList를 이용해 접근했다)
Hash Table은 문자열 탐색에 매우 적합하다.
'myt-algorithm-practice > Samsung SW Certi Pro' 카테고리의 다른 글
[Algorithm][C++] BOJ 5052: 전화번호 목록 (Trie) (0) | 2022.01.13 |
---|---|
[Algorithm][Data Structure] Trie (0) | 2022.01.13 |
[Algorithm][C++] BOJ 10825: 국영수 (Priority Queue, Heap) (0) | 2021.11.25 |
[Algorithm][C++] BOJ 1764: 듣보잡 (Hash Table + Merge Sort) (0) | 2021.11.23 |
[Data Structure][C++] Heap (Min Heap) (0) | 2021.11.23 |