본문 바로가기

자료구조 & 알고리즘

(7)
모노톤 스택 / 큐 / 덱 monotone 이라고 한다면 증가하고 있거나 감소하는 등의 (mono- ) 일정한 경향을 보임을 뜻한다. 그러한 형태를 띠는 스택, 큐, 덱인 것이다. 모노톤이라고 해서 한 방향을 띠긴 하지만, 모든 데이터를 담는 것은 아니다. 필요가 없어진 데이터는 버릴 수 있어야 하고, 필요가 없는 데이터는 기록조차 하지 않는다. 하지만 보통 이 방법을 통해 시간 복잡도를 O(N)으로 줄일 수 있어서 매우 강력하다고 생각한다. 다양한 활용처가 있겠지만, 이 포스트에서는 특정 범위내의 최대 / 최소를 구하는 방법에 대해 알아보고자 한다. 보통 최소값, 최대값 등을 구하기 위해 정렬을 한다. 정렬에도 다양한 방법이 있다. 하지만 정렬은 모든 데이터가 주어졌을 때 사용 가능하다. 더 이상 생성, 수정, 삭제 등의 연산이..
다이나믹 프로그래밍 (동적 계획법) - Dynamic Programming 다이내믹이라고 할지 다이나믹이라고 할지 참 고민이 된다... 다이나믹 프로그래밍은 정말 많은 곳에 쓰이며, 정말 유용하고 때로는 정말 '다이나믹'하게 어렵기도 하다. 문제를 풀다보면 다이나믹 프로그래밍으로 풀리는 문제들에 대한 느낌 같은 것이 있다. 주로 연속된 정점들이 각각 동일한 옵션을 가질 때이다. 옵션이 m이고 정점의 갯수가 n이라면, 모든 케이스를 완전 탐색하기 위해 O(m^n) 이 걸릴 것 같은 문제들. 하지만 다이나믹 프로그래밍은 이것을 O(nm) 에 해결해준다. 즉, 각 옵션이 행이 되고, 각 정점들이 열에 배치되는 형태가 된다. 각 정점에서 어떤 옵션을 택했을 때 어떤 결과가 되는지를 기록해 나가는 것이다. 그리고 중요한 점은 그 결과들이 누적될 때 어떻게 처리해야 하는지이다. 필자가 생..
유니온 파인드 (Union-Find) (disjoint set) (분리 집합) 유니온 파인드는 익히기도 쉽고, 응용 범위도 넓어서 아주 좋아하는 편이다. 간단한 유파는 구현도 쉽고. 꼭 PS가 아니라도 프로그래밍을 하다 보면, 뭔가 동시적으로 (concurrently or simultaneously) 값을 바꾸는 등의 작업을 구현하고 싶을 때가 참 많다. 2가 1의 자식 노드인데, 1의 값을 변경함으로써 2도 어떠한 처리를 해주거나, 우선순위 큐에 이미 들어있는 값인데, 어떤 처리를 통해 그 안의 값이 바뀌면서 순서가 역전되거나, 복잡하게 얽힌 그래프 속에서 하나의 정점만 바꿔도 그 안에 연결된 모든 정점을 같이 바꾼다거나,... 그럴 때 마치 집합처럼 정점들을 엮어주고, 빠르게 처리를 해줄 수 있는 것이 바로 유니온 파인드이다. 유니온 파인드는 유니온 함수와 파인드 함수 2가지를..
LIS - 가장 긴 증가하는 부분 수열 LIS는 이분탐색을 사용하는 기법이다. Longest Increasing Subsequence의 약자로써, 가장 긴 증가하는 부분 수열을 의미한다. 이에 대해 이해하면, 사실 가장 긴 감소하는 부분 수열에도 똑같이 응용 가능하다. [어떤 수를 어디에 놓을지]를 이분탐색으로 해결하는 것이 핵심이다. 위의 그림과 같이, [4, 2, 1, 5, 6, 3] 이라는 수열이 있다고 예를 들자. 이때 가장 긴 증가하는 부분 수열을 찾고자 할 때, 위에 일일이 적은 대로 앞에서부터 하나씩 골라서 확인해볼 수 있을 것이다. 그럼 방식은 2중 for-loop구조를 갖게 되므로, O(n^2)의 시간복잡도를 갖게 된다. 당연히 좋은 방법이 아니다. 위의 그림을 보자. 가장 긴 증가하는 부분 수열을 담을 LIS벡터 또는 배열을..
강한 연결 요소 - Strongly Connected Component (SCC) 개인적으로 그래프, 트리 등을 좋아하는 편이다. 이 알고리즘도 그래서 매우 재미있게 익힐 수 있었다. 강한 연결 요소는 DG (Directed Graph, 단방향 그래프)에서 사이클을 찾는 방법이다. 그리고 그 사이클은 포함할 수 있는 모든 정점을 최대한으로 포함시켜준다. - 사이클을 이룰 수 있는 최대 크기 파악 가능 (하나의 사이클을 이루는 최대한 많은 정점 모두 포함) - 사이클의 총 개수 - 사이클을 이루는 정점 번호 - 사이클을 하나의 정점으로 치환 후 위상정렬과의 연계 등등 다양한 기능을 수행한다. 본 포스팅에서는 코사라주 알고리즘으로 SCC를 찾아보겠다. 기본적인 방식은 DFS를 통해 하나의 정점에서 도달할 수 있는 최대한 먼 곳에서 가까운 순으로 번호를 달아주고, 역방향 그래프 상에서 다시..
위상정렬 - topological sort (비선형 자료구조의 선형화) 비교적 빠른 습득이 가능하고, 효용성도 좋은 알고리즘이라고 생각한다. 문제를 보면 위의 그림과 같이, A,B,C,D가 만드는 쌍(pair)에 대한 관계를 표현하고, 이를 통해 일종의 논리적 체인을 구성해야 하는 일이 있다. 그리고 아래와 같이, 그래프 상에서 DP를 해야하는 경우도 있다. 위의 그림을 조금 더 살펴보자. 위에서 처럼 A에 1을 놓고 전파를 시작한다. A에서 갈 수 있는 정점은 B와 C이므로 B와 C에 A로부터 받은 1을 합산해준다.(모든 정점의 초기값은 0이었다, A를 제외하고.) 위와 같이, E까지 전파하면, BFS를 돌렸을 때, 모든 정점에 대한 방문체크가 끝나고, 그림에서와 같은 값을 갖게 된다. 하지만 이는 올바르지 않다. 전파하는 와중에 값이 변경된 정점이 있기 때문이다. C의 ..
이분탐색 기본적이면서도 너무나도 강력한 이분탐색에 대한 정리를 하고자 한다. 이분탐색이란 말 그대로 일정한 구간, 범위 등을 2개로 나누어 탐색 범위를 좁혀나가는 것을 말한다. 시간복잡도를 따질 때 log N이 붙는 경우가 많은데, 이 로그의 밑은 보통 2를 쓴다. log가 붙었다는 것은 이분탐색 등이 사용되었다는 것을 의미하는 경우가 많다. 4라는 숫자에 밑이 2인 로그를 씌우면 2가 된다. 2의 11승인 2048에 로그를 씌우면 11이 되어버린다. 이것이 의미하는 것은 2048개의 원소를 완전탐색하기 위해서 2048번 일일이 확인하지 않아도, 단 11번 만에 전 범위를 볼 수 있다는 뜻이다. 2048개 숫자를 일종의 이진트리로 재구성하였을 때 그 깊이가 11이라는 의미도 된다. 2048 대 11은 드라마틱하게..