검 지 Offer - 009 - 피 보 나치 수열
우 객 OJ: 피 보 나치 수열
구도 OJ:http://ac.jobdu.com/problem.php?pid=1387
GitHub 코드: 009 - 피 보 나치 수열
CSDN 문제 풀이: 검 지 Offer – 009 - 피 보 나치 수열
우 객 OJ
구도 OJ
CSDN 문제 풀이
GitHub 코드
피 보 나치 수열
1387 - 피 보 나치 수열
검 지 Offer – 009 - 피 보 나치 수열
009 - 피 보 나치 수열
참고:
검 지 Offer 면접 문제 9 (자바 버 전) 피 보 나치 수열
O (logn) 시간 복잡 도 Fibonacci 수열 구하 기
검 지 offer 9 번 문제 및 확장 피 보 나치 수열
제목
제목 설명
모두 가 피 보 나치 수열 을 알 고 있 습 니 다. 지금 은 정수 n 을 입력 하 라 고 요구 하고 있 습 니 다. 피 보 나치 수열 의 n 번 째 항목 을 출력 해 주 십시오.
전달 공식
우 리 는 쉽게 전달 공식 f (n) = * = 0, n = 0 * = 1, n = 1 * = f (n - 1) + f (n - 2) 를 생각 했 기 때문에 우 리 는 바로 다음 과 같은 재 귀 코드 를 생각 했다.
int Fibonacci(int n)
{
if(n <= 1)
{
return n;
}
else
{
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}
근 데 죄송합니다.사실 재 귀적 인 방법 으로 계산 하 는 시간 복잡 도 는 n 의 지수 방식 으로 점점 증가한다.독자 들 은 피 보 나치 의 100 항 을 구 해도 무방 하 다.
재 귀적 전개 - 교체 방법 O (N)
그래서 우 리 는 가장 일반적인 방법 으로 전달 공식 을 펼 칠 수 밖 에 없다.
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public:
int Fibonacci(int n)
{
if(n <= 1)
{
return n;
}
long one = 0;
long two = 1;;
long res = 0;
for(int i = 2; i <= n; i++)
{
res = one + two;
one = two;
two = res;
}
return res;
}
};
int __tmain( )
{
Solution solu;
cout <<solu.Fibonacci(3) <<endl;;
return 0;
}
이 알고리즘 은 아직 가장 빠 른 방법 이 아니다.다음은 시간 복잡 도가 O (logn) 인 방법 을 소개 한다.
시간 복잡 도 는 O (logn) 이지 만 실 용적 이지 못 한 알고리즘 입 니 다.
이런 방법 을 소개 하기 전에 먼저 수학 공식 을 소개 한다.
{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1
(주: {f (n + 1), f (n), f (n), f (n - 1)} 은 행렬 을 표시 합 니 다. 행렬 에서 첫 번 째 줄 의 첫 번 째 열 은 f (n + 1) 이 고, 첫 번 째 줄 의 두 번 째 열 은 f (n) 이 며, 두 번 째 줄 의 첫 번 째 열 은 f (n - 1) 입 니 다.)
이 공식 이 있 으 면 f (n) 를 요구 합 니 다. 우 리 는 행렬 {1, 1, 1, 0} 의 n - 1 차방 만 구 해 야 합 니 다. 행렬 {1, 1, 1, 0} 의 n - 1 차방 결과 의 첫 번 째 줄 은 f (n) 이기 때 문 입 니 다.이 수학 공식 은 수학 귀납법 으로 증명 하기 어렵 지 않다.관심 있 는 친 구 는 스스로 증명 해도 무방 하 다.
현재 문 제 는 행렬 {1, 1, 1, 0} 의 곱셈 으로 바 뀌 었 습 니 다.만약 에 간단하게 0 부터 순환 을 시작 하면 n 제곱 은 n 차 연산 이 필요 하고 앞의 방법 보다 빠 르 지 않 습 니 다.그러나 우 리 는 곱셈 의 다음 과 같은 성질 을 고려 할 수 있다.
/ an/2*an/2 n
an=
\ a(n-1)/2*a(n-1)/2 n
n 제곱 을 요구 하면 우 리 는 먼저 n / 2 제곱 을 구하 고 n / 2 의 결 과 를 제곱 한다.n 을 구 하 는 문 제 를 큰 문제 로 본다 면 n / 2 를 구 하 는 것 을 작은 문제 로 본다.이런 큰 문 제 를 하나 또는 여러 개의 작은 문제 로 분해 하 는 사고방식 을 우 리 는 그것 을 분 치 법 이 라 고 부른다.이렇게 n 제곱 을 구하 면 logn 차 연산 만 필요 합 니 다.
이런 방식 을 실현 하려 면 먼저 2 를 정의 해 야 한다.×2 의 행렬, 그리고 행렬 의 곱셈 과 곱셈 연산 을 정의 합 니 다.이 연산 들 이 정 의 된 후에 남 은 일 은 매우 간단 해 졌 다.완전한 실현 코드 는 다음 과 같다.
원리: 관찰: a (n) = a (n - 1) + a (n - 1) + a (n - 2) = 2 * a (n - 2) + a (n - 3) = 3 * a (n - 3) + 2 * a (n - 3) + 2 * a (n - 4) = 5 * a (n - 4) + 3 * a (k) * a (n - k + 1) + a (n - k + 1) + a (n - k - 1) + a (k - 1) * a (n - k - 1) * a (n - k) 1) * a (n - k) 1 (n - k) 1) * a (n - k) 1) * a (k - k) 1) * a (k - k) 1) * a (k - k) 1) * a (k) 1) 1 (k (k) + a (k - 1)] + a (k - 1) * a (k) = a (k) ^ 2 + 2 * a (k) * a (k - 1) 2,만약 n = 2k - 1 득 a (2k - 1) = a (k) * a (k) + a (k - 1) * a (k - 1) = a (k) ^ 2 + a (k - 1) ^ 2
코드 는 다음 과 같다.
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public :
static int pre;
static int post;
int temp;
int Fibonacci(int n)
{
/** * Fibonacci : * pre: Fibonacci(n) * post: Fibonacci(n-1) */
// if n = 0 #=> 0
// else n = 1 || n = 2 #=> 1
if(n <= 2)
{
if (n == 0) return 0;
pre = 1;
post = 1;
return pre;
}
// n , ,
// pre: f(n) = f(n - 1) + f(n - 2)
// post: f(n - 1) = f(n) - f(n - 2)
if(n%2 == 1)
{
Fibonacci(n-1);
pre = pre + post;
post = pre - post;
return pre;
}
// n
// ,f(n) f(n/2) :
//
// n = 2k:
// f(2k) = f(k) * f(k + 1) + f(k-1) * f(k)
// = f(k) * [f(k) + f(k - 1)] + f(k-1) * f(k)
// = f(k) ^ 2 + 2 * f(k) * f(k - 1)
// n = 2k-1:
// f(2k - 1) = f(k) * f(k) + f(k - 1) * f(k - 1)
// = f(k)^2 + f(k - 1)^2
//
Fibonacci(n/2);
temp = pre;
// f(2k) = f(k)^2 + 2 * f(k) * f(k - 1)
pre = pre * pre + 2 * pre * post;
// f(2k - 1) = f(k) * f(k) + f(k - 1) * f(k - 1)
post = temp*temp + post*post;
return pre;
}
};
int Solution::pre = 0;
int Solution::post = 0;
int __tmain( )
{
Solution solu;
cout <<solu.Fibonacci(3) <<endl;;
return 0;
}
한 단계 확장
제목 설명
개구리 한 마 리 는 한 번 에 1 단 계단 을 뛰 어 올 라 갈 수도 있 고 2 단 계단 을 뛰 어 올 라 갈 수도 있다.이 개구리 가 n 급 계단 을 뛰 어 올 라 가 는 데 는 모두 몇 가지 점프 방법 이 있 습 니까?
분석 하 다.
한 번 에 한 단계 만 뛰 거나 두 단계 만 뛰 면 N 단계 로 나 눌 수 있 습 니 다.
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public:
int jumpFloor(int n)
{
if(n <= 2)
{
return n;
}
long one = 1;
long two = 2;;
long res = 0;
for(int i = 3; i <= n; i++)
{
res = one + two;
one = two;
two = res;
}
return res;
}
};
int __tmain( )
{
Solution solu;
cout <<solu.jumpFloor(2) <<endl;;
return 0;
}
확장 2 – 변태 계단 뛰 어 내리 기
제목 설명
개구리 한 마리 가 한 번 에 1 단 계단 을 올 라 갈 수도 있 고, 2 단 계단 을 올 라 갈 수도 있 고, n 단 계단 을 올 라 갈 수도 있다.이 개구리 가 n 급 계단 을 뛰 어 올 라 가 는 데 는 모두 몇 가지 점프 방법 이 있 습 니까?
분석 하 다.
본 문제 에 대하 여 전 제 는 n 개의 계단 에 n 단계 의 도약 법 이 있다 는 것 이다.분석 은 다음 과 같다.
f (1) = 1 f (2) = f (2 - 1) + f (2 - 2) / / f (2 - 2) 는 2 단계 1 회 2 단계 점프 횟수 를 나타 낸다.f(3) = f(3-1) + f(3-2) + f(3-3) … f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n)
설명:
코드
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public :
int jumpFloorII(int target)
{
if (target <= 0)
{
return -1;
}
else if (target == 1)
{
return 1;
}
else
{
return 2 * jumpFloorII(target - 1);
}
}
};
int __tmain( )
{
Solution solu;
cout <<solu.jumpFloorII(2) <<endl;;
return 0;
}
혹은
class Solution
{
public :
int jumpFloorII(int target)
{
if (target <= 0)
{
return -1;
}
else
{
return pow(2, target - 1);
}
}
};
아니면 더 효율 적 인...
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public :
int jumpFloorII(int target)
{
long long ret;
if(target >= 32)// 8 , ,
{
ret = 1 << 30;
ret = ret << (target - 31);
}
else
{
ret = 1 << (target - 1);
}
return ret;
}
};
int __tmain( )
{
Solution solu;
cout <<solu.jumpFloorII(2) <<endl;;
return 0;
}
확장 3 – 사각형 덮어 쓰기
제목 설명
우 리 는 2 * 1 의 작은 사각형 으로 가로 또는 세로 로 더 큰 사각형 을 덮 을 수 있다.n 개 2 * 1 의 작은 사각형 으로 2 * n 의 큰 사각형 을 중첩 없 이 덮 는 방법 은 모두 몇 가지 가 있 습 니까?
분석 하 다.
2 * n 의 직사각형 방법 수 는 f (n) 로 정의 합 니 다.
첫 번 째 2 * 1 의 작은 사각형 은 큰 사각형 의 왼쪽 을 덮 고,
코드
#include <iostream>
using namespace std;
//
#define __tmain main
#ifdef __tmain
#define debug cout
#else
#define debug 0 && cout
#endif // __tmain
class Solution
{
public:
int rectCover(int n)
{
if(n == 0)
{
return 1;
}
else if(n == 1)
{
return 1;
}
long one = 1;
long two = 1;
long res = 0;
for(int i = 2; i <= n; i++)
{
res = one + two;
one = two;
two = res;
}
return res;
}
};
int __tmain( )
{
Solution solu;
cout <<solu.rectCover(2) <<endl;;
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
오픈 소스 Github 기여 방법 👯♀️소개 , 첫 풀/병합 요청 작성을 연습할 수 있는 오픈 소스 리포지토리입니다. index.html 파일을 열면 이와 동일한 지침을 찾을 수 있습니다. 시작하자! 어떻게 결론 , 당신과 같은 다른 개발자들과 협업할 수...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.