[백준 / Java] 1003번: 피보나치 함수 (DP)

2025. 2. 18. 10:52·CS & Algorithm


코테99 21일차 문제는 백준 1003번 '피보나치 함수'다.

 



 문제 이해

이 문제는 피보나치 함수의 재귀 호출 과정에서 0과 1이 몇 번 출력되는지를 계산하는 문제다. 일반적인 피보나치 수열을 구하는 방식이 아니라, 특정 값이 반환될 때마다 몇 번 호출되는지를 파악해야 한다.

예를 들어, fibonacci(3)을 호출하면 다음과 같은 과정이 진행된다:

fibonacci(3) -> fibonacci(2) + fibonacci(1)
fibonacci(2) -> fibonacci(1) + fibonacci(0)
fibonacci(1) = 1 (출력: 1)
fibonacci(0) = 0 (출력: 0)
fibonacci(2) 결과 = 1 (출력: 1)
fibonacci(3) 결과 = 2 (출력: 1)

위 과정에서 0은 1번, 1은 2번 출력된다.

이처럼 N값에 따라 0과 1이 호출되는 횟수를 빠르게 계산하는 방법을 찾아야 한다.


접근 방법

1. 초기 접근 (재귀 사용)

  • 피보나치 함수를 그대로 재귀 호출하면 중복 연산이 너무 많아진다.
  • fibonacci(40)을 단순 재귀로 구현하면 약 10억 번 이상 호출될 수 있어 시간 초과가 발생한다.

2. 변경된 접근 (DP 활용)

  • 피보나치 수열의 특성을 이용해 0과 1이 출력되는 횟수도 피보나치 형태로 증가함을 이용한다.
  • 즉, count0[n]과 count1[n]은 다음과 같은 점화식을 따른다:
    • count0[n] = count0[n-1] + count0[n-2]
    • count1[n] = count1[n-1] + count1[n-2]
  • 이를 이용해 Dynamic Programming (DP) 방식으로 미리 값을 계산해두면, 각 테스트 케이스에서 O(1)의 시간 복잡도로 답을 구할 수 있다.

알고리즘 진행 순서

  1. 배열을 선언하여 DP 테이블을 저장 (dp[41][2] → 최대 N이 40이므로 41까지 선언)
  2. 기본 값 설정
    • dp[0][0] = 1, dp[0][1] = 0 (fibonacci(0) → 0이 1번, 1이 0번 출력)
    • dp[1][0] = 0, dp[1][1] = 1 (fibonacci(1) → 0이 0번, 1이 1번 출력)
  3. 점화식을 활용해 DP 테이블을 채움 (N=2부터 N=40까지 반복)
    • dp[n][0] = dp[n-1][0] + dp[n-2][0]
    • dp[n][1] = dp[n-1][1] + dp[n-2][1]
  4. 각 테스트 케이스에서 dp[N][0]과 dp[N][1]을 출력

구현 코드

package Boj;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Boj1003 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        int T = Integer.parseInt(br.readLine());

        int[][] dp = new int[41][2];

        // 초기값 설정
        dp[0][0] = 1;
        dp[0][1] = 0;

        dp[1][0] = 0;
        dp[1][1] = 1;

        for (int i = 2; i <= 40; i++) {
            dp[i][0] = dp[i - 1][0] + dp[i - 2][0];
            dp[i][1] = dp[i - 1][1] + dp[i - 2][1];
        }

        for (int t = 0; t < T; t++) {
            int N = Integer.parseInt(br.readLine());
            sb.append(dp[N][0]).append(" ").append(dp[N][1]).append("\n");
        }

        System.out.print(sb);
    }
}

 


회고

  • 단순한 재귀 구현이 항상 좋은 것은 아니다. 중복 연산이 많을 경우 DP를 고려해야 한다.
  • 문제에서 "큰 값을 입력으로 받아도 효율적으로 해결해야 한다"는 점을 유의해야 한다.
  • 피보나치 수열은 DP로 해결하는 것이 가장 효율적이다.
  • 출력 속도를 고려해 StringBuilder를 사용하는 것이 좋다.

추가 최적화 가능성

  • dp 배열을 전역 변수로 선언하면 main() 내에서 매번 배열을 생성할 필요 없이 최적화 가능하다.
  • 배열 없이 변수 2개만 사용해도 해결할 수 있다. (공간 복잡도 O(1))

'CS & Algorithm' 카테고리의 다른 글

[백준 / Java] 9251번: LCS (DP)  (0) 2025.02.19
[백준 / Java] 11053번: 가장 긴 증가하는 부분 수열 (DP)  (0) 2025.02.19
[백준 / Java] 19598번: 최소 회의실 개수 (그리디)  (0) 2025.02.15
[백준 / Java] 1946번: 신입 사원 (그리디)  (1) 2025.02.14
[백준 / Java] 17053번: 맥주 축제 (그리디)  (0) 2025.02.13
'CS & Algorithm' 카테고리의 다른 글
  • [백준 / Java] 9251번: LCS (DP)
  • [백준 / Java] 11053번: 가장 긴 증가하는 부분 수열 (DP)
  • [백준 / Java] 19598번: 최소 회의실 개수 (그리디)
  • [백준 / Java] 1946번: 신입 사원 (그리디)
whatdoyumin
whatdoyumin
안녕하세요, 꾸준히 성장하는 개발자..... 입니다
  • whatdoyumin
    whatdoyumin 님의 블로그
    whatdoyumin
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Frontend
      • Backend
      • Study & Course
      • CS & Algorithm
      • DevOps & Infra
      • Certification
      • Database
      • Project
      • atc.
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    99클럽 #코딩테스트준비 #개발자취업 #항해99 #til
    자바스크립트 코테
    githubworkflow
    코드리뷰자동화
    zustand
    Spring
    백엔드
    브루트포스
    Saa
    frontend
    탐색알고리즘
    타입스크립트
    백트래킹
    클라우드
    coderabbit
    devops
    ai코드리뷰
    Pruning
    TypeScript
    개발자팁
    백준 #백준2805번 #나무자르기 #이분탐색 #알고리즘
    전역상태관리
    코드래빗
    github자동리뷰
    AWS자격증
    결제로직
    99클럽 #코딩테스트준비 #개발자취업 #항해99 #til#dp#동적계획법#코테#백준
    완전탐색
    ResponseEntity
    99클럽 #코딩테스트준비 #개발자취업 #항해99 #til #알고리즘 #브루트포스 #백준 #오목 #완전탐색 #코딩테스트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
whatdoyumin
[백준 / Java] 1003번: 피보나치 함수 (DP)
상단으로

티스토리툴바