자료구조와 알고리듬 With Java
Java 큰 수의 피보나치 수열의 값은?
계란💕
2023. 11. 2. 16:31
- 피보나치(Fibonacci) 수열이란?
- 1, 1, 2, 3, 5, 8, .. 와 같이 f(x) = f(x - 2) + f(x - 1); 을 만족하는 수열을 말한다. (첫 항: f(0) = 0 또는 f(1) = 1)
- 아주 큰 자연수 n에 대하여 피보나치 수열의 n 번째 값은 어떻게 구할 수 있을까?
첫 번째 시도 [Long]
- static 으로 선언한 List<Long> 안에 하나씩 값을 넣어준다. list = [1, 1, 2,3, 5, ...]
- 해당 리스트에 메모이제이션을 적용했다.
<hide/>
static List<Long> list = new ArrayList<>();
private static void fiboFunc(int idx) {
if (idx == 1 || idx == 2) {
list.add(idx, 1L);
return;
}
list.add(idx, list.get(idx - 2) + list.get(idx - 1));
}
결과
- cf) Java에서 Long으로 표현할 수 있는 최댓값: 922 3372 0368 5477 5807(19자리)
- 따라서, 93 번째 부터는 stack overflow로 인한 음수가 나온다.
- static으로 변수를 선언했는데 반드시 필요한 상황은 아니어서 다음 시도에는 제거했다.
두 번째 시도 [List에 모두 담는 방식]
- 한계가 있는 Integer, Long 을 넘어서 더더욱 큰 정수를 활용할 수 있도록 BigInteger를 적용한다.
- 그러나 이 방식은 List에 값을 모두 담기 때문에 n번째 피보나치 값을 구하고자 할 때에는 비효율적이다.
<hide/>
private static void fiboFunc(int n) {
long start = System.currentTimeMillis();
list.add(0, BigInteger.ZERO);
list.add(1, BigInteger.ONE);
BigInteger result = BigInteger.ZERO;
for (int i = 2; i <= n; ++i) {
result = list.get(i - 2).add(list.get(i - 1));
list.add(i, result);
if (i == n) {
long end = System.currentTimeMillis();
System.out.println("duration " + (end - start));
System.out.println(result);
}
}
}
결과
- 100000번째의 피보나치 수를 구하는데 걸린 시간: 223
세 번째 시도 [List 없이 두 개의 변수 돌려써서 결과만 반환]
- 위에서는 List에 하나씩 담아서 매번 읽어오는 방식으로 구현했다.
- 이번에는 두 개의 BigInteger 인스턴스 a, b 두 개를 만들어서 더해서 result에 저장하는 방식으로 구현했다.
- n번째 값을 구하기 이전 값들을 굳이 저장하지 않기 때문에 시간이 짧다.
<hide/>
private static void fiboFunc(int n) {
long start = System.currentTimeMillis();
BigInteger a = BigInteger.ZERO;
BigInteger b = BigInteger.ONE;
BigInteger result = BigInteger.ZERO;
for (int i = 2; i <= n; i++) {
result = a.add(b);
if (i == n) {
long end = System.currentTimeMillis();
System.out.println("duration " + (end - start));
System.out.println(result);
return;
}
a = b;
b = result;
}
}
결과
- 100000번째의 피보나치 수를 구하는데 걸린 시간: 166
- 배열이나 목록으로 수열 전체가 필요하지 않은 이상 이 방법이 가장 효율적이고 시간이 단축된다.