토끼와 거북이 알고리즘은 선형으로 이루어졌거나 링크드리스트 자료구조에서 Cycle 이 존재하는지 찾아내고 그 Cycle 의 시작지점을 알아내는데 유용하다
이 알고리즘을 요약하면
거북이는 한 번에 한 칸을 가고 토끼는 한 번에 두 칸을 보낼때
만약 Cycle 이 존재한다면 둘은 결국 만난다.
Cycle 이 존재하지않는다면 토끼가 null 이 된다.
이 알고리즘을 수학적으로 증명해보자
Cycle 이 존재하지 않는 경우 토끼가 리스트의 끝으로 가서 결국 null 을 가리키게되는 건 자명하므로 생략한다.
토끼가 두 칸을 가고 거북이가 한 칸을 갈 때 둘은 무조건 만난다.
용어를 정의하자
토끼가 움직이는 거리를 h(hare 의 줄임말) 거북이가 움직이는 거리를 t(tortoise 의 줄임말) 라고 하자 그러면
h = 2t
이다. 토끼가 거북이의 두 배를 간다.
우리가 증명해야 하는 건
(t+d) mod m = t
이다. 여기서 d 는 임의의 거리를 의미하고 m 은 Cycle 의 길이를 의미한다. 수식을 그대로 풀어보면 거북이가 간 거리 t 로부터 d 만큼의 거리를 더 간 토끼의 위치를 Cycle 의 길이 m 으로 modular 연산했을 때 거북이의 값과 똑같은 값이 나오면 둘은 같은 위치라는 의미다.
즉, Cycle 이 존재할 때 둘이 아직 만나지 않았다면 거북이가 위치한 t 로부터 토끼는 얼마간 떨어져있다. 얼마인지는 모른다. 하지만 토끼는 거북이의 2배를 가기 때문에 토끼가 간 거리는 (t + d) 가 된다. 역시 d 가 얼마인지는 모른다. 만약 여기서 Cycle 의 길이만큼 modular 연산을 해줬을 때 t 와 같다면 토끼와 거북이는 한 자리에 있다.
h = 2t 이기 때문에 h/2 = t 이다.
위 공식을 대입해보면
((h/2) + d) mod m = h/2
= (h + 2d) mod 2m = h
= (h + 2d) = ( 2m * K ) + h, k 는 어떤 정수다.
= 2d = 2m * K
= d = m * K
결국 d = m * K 이다
K 는 어떤 정수로서, 토끼가 얼마나 많이 Cycle 을 돌았는지 나타낸다.
m 은 Cycle 의 전체 길이를 의미한다. 즉 d 는 Cycle 을 몇바퀴 돌았는지 나타낸다
아까 봤던 이 공식을 기억하는가?
(t+d) mod m = t
여기서 d 는 그저 Cycle 을 몇 번 돌았는지 나타낼 뿐이므로 '위치'의 관점에서 무시할 수 있다. Cycle 을 100만번 돌아도 결국 같은 자리로 돌아오기 때문이다.
따라서 토끼는 무조건 거북이와 만난다.
토끼와 거북이가 만났을 때 거북이만 다시 시작지점으로 옮긴 후 토끼와 거북이 모두 한 칸씩 이동시키면 둘이 만나는 지점이 바로 Cycle 의 시작지점이다.
용어를 정의하자
a: 시작지점에서 Cycle 시작지점까지의 거리
m: Cycle 의 길이
b: Cycle 안에서 토끼와 거북이가 만날 때 까지의 거리, 즉 Cycle 시작지점으로부터 토끼와 거북이가 만나는 지점까지의 거리
토끼와 거북이가 만난다면 토끼가 움직인 거리는 a + b + j*m 이다. j 는 어떤 정수이다.
거북이가 움직인 거리는 a + b 이다.
토끼가 거북이보다 두 배 빠르게 움직이기 때문에
2(a + b) = a + b + jm
= 2a + 2b = a + b + jm
= a + b = jm
= a = jm - b
결국
a = jm - b 가 된다.
이걸 더 풀어보면
a = m - b + (j-1)m
a = m - b + km
m - b = km - a
가 된다.
근데 m 은 Cycle 전체의 길이이기 때문에 '위치'의 관점에선 무시해도 상관없는 값이다.
결과 b 와 a 는 '같은 거리에 있다.'고 말할 수 있다. 따라서 시작지점으로 옮긴 거북이와 Cycle 에 남아있는 토끼를 한칸씩 이동시키면 둘이 만나는 지점이 Cycle 의 시작지점이다.
'알고리즘' 카테고리의 다른 글
Leetcode 127 Word Letter (0) | 2022.02.12 |
---|---|
백준 2098 외판원 순회문제 (0) | 2022.02.06 |
[LeetCode] 13. Roman to Integer (0) | 2021.07.10 |
백준(BOJ) 1765번 피자 굽기 자바(java) (0) | 2020.06.07 |
백준(BOJ) 1033번 칵테일 (0) | 2020.05.08 |