PGR21.com
- 자유 주제로 사용할 수 있는 게시판입니다.
- 토론 게시판의 용도를 겸합니다.
Date 2013/04/14 03:06:30
Name azurespace
Subject [일반] 알고리즘 문제와 그 풀이 #1. Sliding Window

알고리즘 문제를 해결하는 것이 목표인 대회들이 있습니다. 대표적으로는 국제정보올림피아드(IOI)가 있으며 여기에 참여할 국가대표를 뽑기 위한 한국정보올림피아드(KOI), 그 외에도 ACM-ICPC, Topcoder, Codechef 등 여러 오프라인 및 온라인 대회들이 있습니다. 오늘 진행된 구글 코드잼 같은 대회는 성적에 따라서 구글에서 채용하기도 할 정도지요


제가 풀어본 문제들 중 몇가지를 올리고 제가 어떻게 풀었는지 한번 경험을 공유해보고자 합니다.



시간제한: 12초
테스트 케이스당 시간 제한 : 5초
메모리 사용량 제한 : 65536KB


여기 배열이 하나 있습니다 배열의 크기는 n으로 10^6 넘지 않습니다그리고  배열의 왼쪽 끝에서 오른쪽 끝으로 움직이고 있는 슬라이딩 윈도우가 있습니다 윈도우의 길이는 k입니다여러분은 윈도우 안에 보이는 k개의 수만을   있습니다윈도우는  번에  칸씩 오른쪽으로 움직입니다다음은 예제입니다.

 예제는 원문 출처로 가서 보시기 바랍니다.

문제 출처 :  http://poj.org/problem?id=2823



슬라이딩 윈도우가  위치에 있을  보이는 최대값과 최소값이 무엇인지 구하는 것이 여러분에게 주어진 문제입니다.




입력

입력은  개의 줄로 이루어져 있습니다 번째 줄은 배열의 길이와 슬라이딩 윈도우의 길이를 나타내는  개의 정수n k 담고 있습니다다음 줄에 배열의 내용을 나타내는 n개의 정수가 담겨 있습니다.



출력

출력은  개의 줄을 담고 있어야 합니다 번째 줄은 윈도우가 왼쪽에서 오른쪽으로 움직일 때마다 윈도우에 보이는 최소값을 나타냅니다두번째 줄은 최대값입니다.









 



주의 : 지금부터는 이 문제의 풀이입니다. 직접 문제를 풀어보고 싶으신
분들은 읽지 말아주세요. 스포일러 방지 기능이 있으면 좋을텐데 없군요.



Naïve Solution

가장 간단한 풀이는 각 위치에 대해서 슬라이딩 윈도를 직접 대어 보고 최대값과 최소값이 무엇인지 찾는 것입니다. 2중 for문을 통해서 구현하면 되겠죠. O(NK)입니다


소스 코드 : http://ideone.com/c0bBrQ



하지만 이 풀이는 너무나 느립니다. N의 크기가 1000000까지 될 수 있고 K도 마찬가지이므로 이런 경우에는 아무리 코드를 최적화한다 하더라도 시간내에 답이 나오지 않습니다. 


Min-max Heap



 



Heap이라는 자료구조가 있습니다. 이 자료구조의 한 변형인 Min-max Heap은 현재 Heap 안에 들어있는 원소들 중 최소값과 최대값이 무엇인지 상수 시간에 알 수 있으며, 하나의 원소가 삽입되고 제거될 때마다 O(lg N)만큼의 연산이 소요됩니다. (Deap이라는 변형에서도 가능합니다) 그런데 이때 최대값과 최소값 이외의 모든 값에 대해서 어느 위치에 있는지를 하나하나 추적하게끔 구현할 수 있습니다. N의 최대값은 백만인데, 백만개 정도 정수배열을 하나 더 잡는다고 해서 메모리 경계를 초과하지는 않습니다.



 



그러므로 Min-max heap이나 Deap을 사용해서 슬라이딩 윈도우가 오른쪽으로 이동할 때마다 추가되는 수를 자료구조에 집어넣고, 빠져나가는 수를 자료구조에서 빼는 식으로 구현할 수 있습니다. 이렇게 한 경우 시간복잡도는 O(N lg N)입니다. 충분히 시간 내에 나올 수 있지요. 그런데 일반적으로 구현된 라이브러리에는 min, max를 제외한 다른 원소를 추적하는 기능이 없습니다. 어쩔 수 없죠. 원래 그걸 위한 자료구조가 아닌걸요… 직접 구현하는 수밖에 없습니다. 이 방법에 대해서는 따로 코드를 첨부하지 않겠습니다.



 Binary-search Tree


이진 탐색
트리는 이진 트리의 일종으로 각 노드의 왼쪽 자식은 부모 노드가 지닌 값보다 작은 값을 지니고, 오른쪽 자식은 부모보다 큰 값을 갖도록 구성되어 있습니다. 균형잡힌 이진 트리의 경우 데이터의 삽입, 삭제가 O(lg N)만에 가능합니다.
 



그리고 중요한 특징은, 이진 탐색 트리의 최소값과 최대값 역시 O(lg N)에 구할 수 있다는 것입니다. 이 방법 역시 O(N lg N)에 해결이 가능합니다.


소스 코드 : http://ideone.com/V3anCU



Indexed Tree

인덱스 트리라는 자료구조는 완전 이진 트리의 일종인데, 알고리즘 경시에
참여하는 사람들 사이에서 통용되는 이름입니다. 구간 트리라고도 불리는데 일반적인 구간 트리와는 약간
다릅니다.



일단 이 트리는 완전 이진 트리이므로 .N보다 크거나 같은 가장 작은 2의 지수를 M이라 할 때,
2*.M개의 저장공간을 필요로 합니다.


각 노드는 자신이 가리키는 구간을 ‘대표하는’ 값을 지니게 됩니다. 예를 들어 이 문제의 경우 트리의 루트 노드는 Min( Array[0..M-1] ) 또는 대응되는 Max의 값을 가지게 되겠죠. 루트의 왼쪽 노드는 0 ~ M/2-1까지의 구간을 대표하고, 루트의 오른쪽 노드는 M/2 ~ M-1까지를
대표하고.. 이런 식으로 깊이가 한단계 깊어질 때마다 노드가 대표하는 구간의 크기가 절반씩 줄어듭니다. 깊이가 log M이 되면 각각 길이 1의 구간을 대표하고 있게 되죠. (그 위치에 해당하는 Array의 값을 지닌다는 뜻)



 



트리의 갱신은 일단 가장 끝부분의 값을 바꾸고, 부모 노드를 하나씩
타고 올라오면서 값을 갱신해 줍니다. 두 자식의 값을 보고 자기자신을 바꾸는 recursive 함수를 작성하면 되겠죠?



이렇게 하면 임의의 구간에 대한 값을 구하는 건 lg M 개의 노드만 선택하면 어떤 구간이라도 커버가 가능하기 때문에… O(lg M) = O(lg N)입니다. M < 2*N이니까요. 





지금까지 O(N lg N) 솔루션을 보았습니다. 그런데… 사실 이 문제를 해결하는 가장 빠른 알고리즘의 시간복잡도는 O(N)입니다. 믿기시나요?



일단 배열을 2*K-1개씩 쪼갭니다.
K=4이라면 배열을 7개 단위로 자르게 되겠네요. 다음을 봅시다.


A[0]  A[1]   A[2]   A[3]   A[4]  A[5]   A[6]


이때 중앙에서부터 계산을 시작하면 다음과 같은 배열은 O(K)만에
계산이 가능하겠죠?



Min[0..3] Min[1..3] Min[2..3] A[3] Min[3..4] Min[3..5] Min[3..6]


그런데 이걸 잘 보시면요. 이 배열만으로 슬라이딩 윈도우 내에서 최소값이
무엇인지 다 알 수 있어요.


Min[0..3]은 배열 안에 있고요. Min[1..4] = Min[1..3]과 Min[3..4] 중 작은 값이죠.
Min[2..5]는 Min[2..3]과 Min[3..5]중에 작은 값이죠…

어헣 간단하죠?


2*K-1개씩 배열을 나누면 대충 O(N/K)개의 부분배열이 나오죠? 각각의 부분배열에서 최대값과 최소값을 구하는 것은 O(K)만에 되니까 O(N/K) * O(K) = O(N) 이 되는 것입니다.



코드 : http://ideone.com/sduj2J


이 코드는 2007년에 제가 고딩이었던 시절에 작성한 거라 좀 더럽긴 한데 뭐 방법 자체는 충실히 구현하고 있습니다.



 


생각보다 길어졌네요. 과연 시리즈물로 찾아뵐 수 있을는지?


통합규정 1.3 이용안내 인용

"Pgr은 '명문화된 삭제규정'이 반드시 필요하지 않은 분을 환영합니다.
법 없이도 사는 사람, 남에게 상처를 주지 않으면서 같이 이야기 나눌 수 있는 분이면 좋겠습니다."
꿀호떡a
13/04/14 03:07
수정 아이콘
우와 피지알에 알고리즘글이....
13/04/14 03:54
수정 아이콘
재미있게 읽었습니다, 알고리즘의 세계는 무궁무진하군요.
전전에서 컴공으로의 대학원 진학을 생각하는 입장에서, 이런 문제들을 기발한 알고리즘으로 풀어내는 사람들을 보면
존경심과 동시에, 이런 똑똑한 사람들도 있는데 제가 컴공을 하겠다는 게 분수에 맞는 것인가 하는 불안감도 들곤 합니다.

제가 잘 이해하지 못한 것이겠지만... 질문 있습니다.
k가 4이고 고로 7로 배열을 자른다고 하였을 때,
(Min[0..3] Min[1..3] Min[2..3] A[3] Min[3..4] Min[3..5] Min[3..6]) (Min[7..10] Min[8..10] Min[9..10] A[10] Min[10..11] Min[10..12] Min[10..13]) (...)
제가 이해한 대로라면 이렇게 배열이 잘리게 될텐데요,
Min[0..3], Min[1..4], Min[2..5], Min[3..6], 즉 한 "조각" 내에서 최소치를 구하는 것은 두 원소 비교만 하면 되니 자명한데,
Min[4..7], Min[5..8], Min[6..9] 등 두 조각에 걸쳐있는 경우에서 최소치를 구하는 방법은 어떻게 하나요?
앞 네 원소와는 다르게 두 원소 비교만으로는 힘들 것 같아서요.
레필리아
13/04/14 10:34
수정 아이콘
전전에서 컴공 오시는거면.. 하드웨어의 세계로 오시는게 어떨까요??
13/04/14 22:38
수정 아이콘
아키나 임베디드 쪽 말씀하시는 건가요...사실은 머신러닝쪽 생각하고 전과를 결심한 거라서요. 흐흐
azurespace
13/04/14 04:26
수정 아이콘
4로부터 시작하는 2k-1크기 부분배열을 다시 만듭니다 그러니까 부분배열의 시작 인덱스는 k씩 증가하게 되겠지요
태연O3O
13/04/14 04:50
수정 아이콘
재미있게 봤습니다.
신밧드
13/04/14 09:01
수정 아이콘
재미있게 보고싶습니다..
외계어군요
2막2장
13/04/14 09:25
수정 아이콘
학부 전자에 석사 영상처리 전공이라 sliding window가 익숙해서 봤더니, 알고리즘 분야였군요 ㅠㅠ
꽤 다양한 해법이 존재하네요. 성능은 천차 만별이고.. 잘 보고 갑니다.
13/04/14 10:11
수정 아이콘
저와같으시네요.

어느쪽하시는지 크크
13/04/14 09:29
수정 아이콘
트리같은 자료구조쓰면 nlogk아닌가요?
슬라이딩 윈도우보다 많은 크기의 원소를 가질 필요가 없어보이는데요
azurespace
13/04/14 12:47
수정 아이콘
네 맞습니다 뭐 lg n >= lg k라 O표기법으로 틀린건 아니에요 (...)
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회 추천
43194 [일반] 진격의 거인 재미있네요. - 단행본, 스포 유 - [32] tyro13648 13/04/14 13648 0
43192 [일반] 노래 10곡이요. [5] 5161 13/04/14 5161 0
43191 [일반] [국내축구] K리그 클래식 정대세-차두리 맞대결 성사! [27] lovewhiteyou5764 13/04/14 5764 1
43190 [일반] 싸이. 시건방춤 저작권료 지급. [47] Leeka12390 13/04/14 12390 2
43189 [일반] [FA컵] 2013 하나은행 FA컵 2라운드가 전국에서 열렸습니다. [11] lovewhiteyou5533 13/04/14 5533 1
43188 [일반] 그것이 알고 싶다 - 비열한 거리 (조건 사기편) [15] KazYa13109 13/04/14 13109 0
43187 [일반] 뉴스타파 - 조세피난처 특집 [10] 어강됴리7209 13/04/14 7209 0
43186 [일반] 처음으로 당해본.. 인터넷 입금사기. [5] 확고한신념6027 13/04/14 6027 0
43185 [일반] 알고리즘 문제와 그 풀이 #1. Sliding Window [11] azurespace14340 13/04/14 14340 1
43184 [일반] 지식채널e - 개와 고양이에 관한 진실 [8] 김치찌개6698 13/04/14 6698 1
43183 [일반] 덕장 홍명보 , 그의 빛나는 리더쉽이 발휘된 순간들 [4] 김치찌개5211 13/04/14 5211 0
43182 [일반] 미국이 러시아를 핵공격할 경우에 대비한 러시아의 "죽음의 손"시스템 [11] 김치찌개7686 13/04/14 7686 1
43181 [일반] 차 안에서는 조용히 해야됩니다. [64] Eva0108974 13/04/14 8974 24
43180 [일반] 오덕 100선 #0 - 무엇이 나를 오덕으로 만들었나 [8] 삭제됨4144 13/04/14 4144 2
43179 [일반] 오블리비언 – 누구나 다 알고 있는 얘기라면 어떻게 해야 하나…(스포없음) [25] Neandertal6956 13/04/13 6956 0
43178 [일반] NC의 2승. 그리고 한화의 12연패 [64] Leeka10334 13/04/13 10334 0
43177 [일반] 자기계발, 그리고 자기관리. [87] par333k6764 13/04/13 6764 10
43176 [일반] 드라마 직장의 신을 보고 생각난게 있어요 [3] 맹구맹구맹구4387 13/04/13 4387 0
43175 [일반] [독후감] 장 코르미에,『체 게바라 평전』- 인류는 정녕 평화에 도달할 수 있을까 [8] 쌈등마잉3657 13/04/13 3657 0
43174 [일반] 싸이의 신곡 'GENTLEMAN' 뮤직비디오가 공개되었습니다. [116] kimbilly9156 13/04/13 9156 0
43173 [일반] 연산군의 폭정 [4] 눈시BBbr6724 13/04/13 6724 0
43172 [일반] 제가 느낀 한류 [31] 안동섭8212 13/04/13 8212 0
43171 [일반] 뚱뚱하다는이유로 차별받는걸 당연시 해야하나요? [470] 삭제됨11666 13/04/13 11666 3
목록 이전 다음
댓글

+ : 최근 1시간내에 달린 댓글
+ : 최근 2시간내에 달린 댓글
맨 위로