![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/0nVpq/btqFYZIjfTF/JGtZ3Y5LODDcf6z2FmRSyk/img.png)
문제 https://www.acmicpc.net/problem/5446 알고리즘 트라이 풀이 제거해야 하는 문자열과 남겨야 하는 문자열이 주어지고, "문자열"+"*"을 통해 "문자열"로 시작하는 모든 문자열을 제거할 수 있다고 합니다. 접두사를 이용한다는 점에서 트라이를 착안해봅시다. 각 노드마다 $yes$,$no$,$finish$ 를 만들어서 해당 노드를 제거해야하는지(yes), 제거해서는 안되는지(no), 제거해야 하는 문자가 끝나는지(finish)를 구분합니다. 만약 노드의 $yes$와 $no$가 둘 다 True 면 해당 노드를 제거해서는 안됩니다. (노드를 제거한다는 것은 와일드 카드를 사용해서 이후 노드를 보지 않겠다는 의미입니다) 이때 유의해야할 것은, 제거해서는 안 되는 노드에 $finish..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/cnsPvI/btqFTTsUrtg/jmEWGvCDkZpUl3LSTSaSGK/img.png)
문제 https://www.acmicpc.net/problem/3080 알고리즘 Trie 풀이 관찰이 필요한 문제입니다. 예제들을 그림으로 그려 예제 입출력을 이해하도록 합시다. 이를 통해 문제의 답은 (트라이의 자식 수 + 해당 트라이에서 끝나는 단어)의 팩토리얼들의 곱이라는 점을 알아낼 수 있습니다. 이렇게 문제를 풀게 되면 메모리 초과가 발생하게 됩니다. Trie? 선형시간에 원하는 문자열을 찾아낼 수 있는 자료구조입니다. 이를 가능케 하는 것은 각각의 트라이마다 모든 문자들을 가리키는 포인터를 저장하고 있기 때문입니다. 이 때문에 많은 메모리를 사용한다는 단점이 있는 자료구조입니다. 따라서, 필요하지 않은 문자열을 제거해야합니다. Suffix Array & LCP에서 봤듯이, 주어진 문자열을 정렬..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/b5nr5k/btqFPrR15Ui/7pJFJQNTsTiVuKRKYV6z60/img.png)
문제 https://www.acmicpc.net/problem/9249 알고리즘 Suffix Array 풀이 LCS문제입니다. 주어진 두 문자열$A, B$를 합친 후 LCP를 구하게 되면 답을 얻을 수 있습니다. 이때 주의해야 할 점이 있습니다. 인접한 LCP를 검사할 때, 하나의 Suffix는 $A$의 일부를 포함해야 하지만, 나머지 Suffix는 $A$를 포함해선 안된다는 점입니다. 이점을 유의하지 않으면 $A$ 또는 $B$ 내에서만 LCP를 뽑아버리므로 두 문자열의 공통부분 문자열을 얻지 못하게 됩니다. 시간 복잡도는 Suffix Array와 LCP를 구해야 하므로 $O(NlogN+N)$입니다. 코드 #include #define rep(i,n) for(int i=0;i
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/bkBFHU/btqFPrXu1Dc/wCBPfJkbUfe8Oi2ZkEh3HK/img.png)
문제 https://www.acmicpc.net/problem/11479 알고리즘 Suffix Array 풀이 열심히 구한 Suffix Array와 LCP로 우리는 무엇을 할 수 있을까요? 그중 하나인 부분 문자열과 관련된 문제들입니다. 이 문제에선 서로다른 부분 문자열의 개수를 묻고 있습니다. 부분 문자열이란 것은 달리 말하면 Suffix의 Prefix입니다. Banana를 예로 들어보겠습니다. 모든 Suffix를 나열해보면 {Banana,anana,nana,ana,na,a} 가 될 겁니다. 여기서 부분 문자열을 얻기 위해 각각의 Suffix들에 대해 Prefix를 보면 되겠죠. 모든 Suffix 중 Suffix "anana"에서 얻을 수 있는 부분 문자열은 {a,an,ana,anana,anana} 입..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/19Are/btqFNqSOPI6/Lpx3TKbB06EXFS0Sx9VYoK/img.png)
문제 https://www.acmicpc.net/problem/9248 알고리즘 Suffix Array 풀이 문자열에서 가장 어려운 알고리즘인 Suffix Array입니다. 이 글에선 제가 해당 알고리즘을 공부할 때 어려웠던 부분 및 이해하기 위한 선행지식을 간단하게 정리하려고 합니다. Counting sort & Radix sort Counting sort는 non-comparison sort으로 $O(N)$에 정렬을 해주는 알고리즘입니다. 주로 정렬할 데이터에 대한 사전 지식이 있을 때 사용합니다. 사전 지식이란 $k$이하의 정수를 배열을 정렬하라는 문제에서 $k$이하의 정수라는 조건을 의미합니다. 방법은 stable 한 방법과 unstable한 방법이 있는데, 정렬할 데이터가 단일 데이터(정수 1개..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/B3eQY/btqFKmwsZTC/b7uLf7tqjRsx85u6KW7wPk/img.png)
문제 https://www.acmicpc.net/problem/13276 알고리즘 KMP 해설 다양한 풀이가 있는 문제입니다. 라빈 카프를 이용한 해싱, 가장 효율적인 Suffix Array 등 이 있지만 구현이 가장 쉬운 KMP로 풀었습니다. $S$에 대해 두 문자열$A$,$B$가 나타나는 위치를 KMP를 통해 찾은 후, 부분 문자열이 될 수 있는 것들을 담았습니다. $vector$에 직접 부분 문자열을 담게 되면 메모리 초과가 발생하니, $set$을 통해 부분 문자열을 담고, 자연스레 중복도 제거하도록 합시다. 시간 복잡도는 모든 인덱스에서 부분 문자열이 시작하고 끝날 수 있으므로 $O(N^2)$ + 해시 접근입니다. #include #include #define rep(i,n) for(int i=0..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/mgF77/btqFHp7SQ7P/jXQF1HONkxKsPewa5biiH0/img.png)
문제 https://www.acmicpc.net/problem/6206 알고리즘 라빈 카프 해설 https://www.acmicpc.net/problem/3033 3033번 문제에선 두 번 이상 등장하는 패턴 중, 가장 긴 문자열의 길이를 물었지만, 이 문제는 두 번이 아닌 $K$번 등장하는 패턴을 묻고 있습니다. 등장 횟수를 카운트하기 위하여 $set$ 대신 $map$을 사용한 것을 제외하곤 3033번 문제와 동일하게 풀 수 있습니다. ++ 각 우유 샘플이 100만 이하의 정수를 가질 수 있으므로, $BASE$는 100만 이상의 값을 주도록 합시다. 코드 #include #include #define rep(i,n) for(int i=0;i> K; rep(i, N) cin >> arr[i]; int l..
![](http://i1.daumcdn.net/thumb/C148x148/?fname=https://blog.kakaocdn.net/dn/udzoI/btqFD5okbAY/W2SR8nbQUBKiclZhJ02qS1/img.png)
문제 https://www.acmicpc.net/problem/17228 알고리즘 라빈 카프 해설 정원의 쉼터가$N-1$개의 길로 연결되어있다는 점에서 트리임을 알 수 있고, 반대방향으로 이동하는 것을 금지한다는 조건에서 DFS접근방식을 생각했습니다. 만영이 취향의 문자열을 해싱한 후, DFS를 수행하며 수행과정에서 얻는 문자열 또한 해싱하며, 해시값이 동일하다면 정답을 카운트해주면 됩니다. 처음 $recur()$ 에서는 롤링 해시할 길이가 없으므로, 가짜 문자인 $를 넣어주었습니다. DFS와 라빈 카프를 이용했으므로 시간 복잡도는 $O(V+E+N)$입니다. 코드 #include #include #define rep(i,n) for(int i=0;i N; adj.resize(N); rep(i, N - 1..
- Total
- Today
- Yesterday
- Fenwick
- SCC
- 이분탐색
- 이분매칭
- spring
- string
- dijkstra
- hld
- DP
- implementation
- greedy
- 스위핑
- 트라이
- Segment tree
- 정렬
- spring boot
- 펜윅트리
- dfs
- 2-SAT
- 세그먼트트리
- kmp
- sorting
- sweeping
- bfs
- 동적계획법
- union find
- knapsack
- Suffix Array
- 좌표압축
- Oracle
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |