매일 알고리즘 시리즈 (19) (n 을 입력 하고 가장 빠 른 방법 으로 이 수열 의 n 항 을 구하 십시오)
제목:
정의 Fibonacci 수열 은 다음 과 같 습 니 다: f (n) = 0 (n=0) f(n) = 1 (n=1, 2) f(n) = f(n-1)+f(n-2) (n > 2) n 을 입력 하고 가장 빠 른 방법 으로 이 수열 의 n 항 을 구하 십시오.
사고방식 1:
나 는 많은 프로그래머 들 이 이 문 제 를 보면 재 귀적 인 방법 으로 이 문 제 를 풀 생각 을 하기 쉽다 고 믿는다. 그러나 너 는 이것 이 결코 가장 빠 른 방법 이 아니 라 는 것 을 알 고 있다.또 다른 방법 은 하나의 For (While) 순환 으로 이 문 제 를 풀 수 있 고 시간 복잡 도 는 O (n) 로 재 귀 하 는 방법 보다 좋 으 며 다음 에 이 두 가지 방법의 코드 를 먼저 제시 하 는 것 이다.
코드 는 다음 과 같 습 니 다:
/*------------------------------------
Fibonacci N .
Copyright by yuucyf. 2011.07.22
-------------------------------------*/
long long FibNItemValue(int i32NItem)
{
if (i32NItem <= 0) return 0;
if (i32NItem >= 1 && i32NItem <= 2) return 1;
return FibNItemValue(i32NItem - 1) + FibNItemValue(i32NItem - 2);
}
long long FibNItemValue_2(int i32NItem)
{
long long int llFirst = 1, llSecond = 1, llNItemValue = 0;
if (i32NItem <= 0) return 0;
if (i32NItem >= 1 && i32NItem <= 2) return 1;
for (int i32I = 3; i32I <= i32NItem; i32I++)
{
llNItemValue = llFirst + llSecond;
llFirst = llSecond;
llSecond = llNItemValue;
}
return llNItemValue;
}
int _tmain(int argc, _TCHAR* argv[])
{
_tprintf(_T("N item value is %u.
"), FibNItemValue(40));
return 0;
}
사고방식 2:
상기 두 가지 방법 은 모두 이 문 제 를 풀 수 있 지만 가장 빠 른 것 이 아니다. 다음은 시간 복잡 도가 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 짝수 \ a(n-1)/2*a(n-1)/2 홀수
n 제곱 을 요구 하면 우 리 는 먼저 n / 2 제곱 을 구하 고 n / 2 의 결 과 를 제곱 한다. 만약 에 n 제곱 을 구 하 는 문 제 를 큰 문제 로 보면 n / 2 를 구 하 는 것 을 작은 문제 로 본다.이런 큰 문 제 를 하나 또는 여러 개의 작은 문제 로 분해 하 는 사고방식 을 우 리 는 그것 을 분 치 법 이 라 고 부른다.이렇게 n 제곱 을 구하 면 logn 차 연산 만 필요 합 니 다.
이런 방식 을 실현 하려 면 먼저 2 를 정의 해 야 한다.×2 의 행렬, 그리고 행렬 의 곱셈 과 곱셈 연산 을 정의 합 니 다.이 연산 들 이 정 의 된 후에 남 은 일 은 매우 간단 해 졌 다.
#include "stdafx.h"
#include <assert.h>
/*------------------------------------
Fibonacci N .
Copyright by yuucyf. 2011.07.22
-------------------------------------*/
///////////////////////////////////////////////////////////////////////
// A 2 by 2 matrix
///////////////////////////////////////////////////////////////////////
typedef struct tagMatrix2By2
{
tagMatrix2By2(long long m00 = 0, long long m01 = 0, long long m10 = 0, long long m11 = 0)
:m_00(m00), m_01(m01), m_10(m10), m_11(m11)
{}
long long m_00;
long long m_01;
long long m_10;
long long m_11;
}S_Matrix2By2;
///////////////////////////////////////////////////////////////////////
// Multiply two matrices
// Input: sMatrix1 - the first matrix
// sMatrix2 - the second matrix
//Output: the production of two matrices
///////////////////////////////////////////////////////////////////////
S_Matrix2By2 MatrixMultiply(const S_Matrix2By2& sMatrix1, const S_Matrix2By2& sMatrix2)
{
return S_Matrix2By2(
sMatrix1.m_00 * sMatrix2.m_00 + sMatrix1.m_01 * sMatrix2.m_10,
sMatrix1.m_00 * sMatrix2.m_01 + sMatrix1.m_01 * sMatrix2.m_11,
sMatrix1.m_10 * sMatrix2.m_00 + sMatrix1.m_11 * sMatrix2.m_10,
sMatrix1.m_10 * sMatrix2.m_01 + sMatrix1.m_11 * sMatrix2.m_11);
}
///////////////////////////////////////////////////////////////////////
// The nth power of matrix
// 1 1
// 1 0
///////////////////////////////////////////////////////////////////////
S_Matrix2By2 MatrixPower(int i32N)
{
assert(i32N > 0);
S_Matrix2By2 sMatrix;
if(i32N == 1)
{
sMatrix = S_Matrix2By2(1, 1, 1, 0);
}
else if(i32N % 2 == 0)
{
sMatrix = MatrixPower(i32N / 2);
sMatrix = MatrixMultiply(sMatrix, sMatrix);
}
else if(i32N % 2 == 1)
{
sMatrix = MatrixPower((i32N - 1) / 2);
sMatrix = MatrixMultiply(sMatrix, sMatrix);
sMatrix = MatrixMultiply(sMatrix, S_Matrix2By2(1, 1, 1, 0));
}
return sMatrix;
}
long long FibNItemValue_3(int i32NItem)
{
int aryRes[2] = {0, 1};
if(i32NItem < 2)
return aryRes[i32NItem];
S_Matrix2By2 sPowerNMinus2 = MatrixPower(i32NItem - 1);
return sPowerNMinus2.m_00;
}
int _tmain(int argc, _TCHAR* argv[])
{
_tprintf(_T("N item value is %u.
"), FibNItemValue_3(50));
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
물체 검출의 평가 지표 IoU의 계산 방법Yolo나 SSD 등 물체 검출에서 평가 지표로 사용되는 IoU에 대해 조사했으므로 정리했습니다. IoU (Intersection over Union)는 두 영역이 얼마나 겹치는지를 나타내는 지표입니다. 두 영역의 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.