Dãy Fibonacci - Bài Tập Python cơ bản
Dãy Fibonacci – Bài Tập Python cơ bản

Bạn nghĩ in dãy Fibonacci chỉ là a, b = 0, 1 rồi print? Đó là tư duy của sinh viên năm nhất.

Trong phỏng vấn tại Big Tech (Google, Meta) hay các dự án Blockchain/Fintech năm 2026, Fibonacci không chỉ là số học. Nó là bài test về quản lý bộ nhớ (Memory Management)độ phức tạp thuật toán (Big O). Nếu bạn viết đệ quy ngây thơ để tính số thứ 100, server sẽ treo, CPU sẽ cháy và bạn sẽ trượt phỏng vấn.

Bài viết này không chỉ dạy bạn code. Nó dạy bạn cách tư duy kiến trúc để biến một bài toán Hello World thành một Microservice chuẩn chỉnh.

Bạn xem thêm:


1. Cấp độ 1

Dãy Fibonacci - Bài Tập Python cơ bản
Dãy Fibonacci – Bài Tập Python cơ bản

1.1. Giải thích khái niệm

Hãy tưởng tượng bạn nuôi thỏ.

  • Tháng 0: Có 0 cặp thỏ.

  • Tháng 1: Mua 1 cặp thỏ sơ sinh.

  • Tháng 2: Cặp thỏ lớn lên (vẫn là 1 cặp).

  • Tháng 3: Cặp thỏ sinh ra 1 cặp con (Tổng: 2 cặp).

  • Tháng 4: Cặp thỏ bố mẹ sinh tiếp, cặp con lớn lên (Tổng: 3 cặp).

Quy luật: Số thỏ tháng này = Số thỏ tháng trước + Số thỏ tháng trước nữa.

Công thức toán học: F(n) = F(n-1) + F(n-2).

1.2. Hello World: 5 Phút Chạy Code

Đây là cách đơn giản nhất, sử dụng vòng lặp (Loop) để tránh lỗi tràn bộ nhớ (Stack Overflow) của đệ quy.

# Cách cổ điển: Dùng vòng lặp
def print_fibonacci_basic(n):
    """
    In ra dãy Fibonacci với n phần tử.
    Độ phức tạp: O(n) - Tuyến tính.
    """
    if n <= 0:
        print("Vui lòng nhập số nguyên dương!")
        return

    n1, n2 = 0, 1
    count = 0

    print("Dãy Fibonacci: ", end="")
    while count < n:
        print(n1, end=" ")
        # Cập nhật giá trị: n1 thành n2, n2 thành tổng
        nth = n1 + n2
        n1 = n2
        n2 = nth
        count += 1
    print() # Xuống dòng

# Test thử
try:
    num = int(input("Nhập số lượng phần tử muốn in: "))
    print_fibonacci_basic(num)
except ValueError:
    print("Lỗi: Phải nhập số!")

Tại sao cách này ổn cho người mới? Dễ hiểu, dễ debug, chạy nhanh với số nhỏ (n < 1000).


2. Cấp độ Freelancer

Dãy Fibonacci - Bài Tập Python cơ bản
Dãy Fibonacci – Bài Tập Python cơ bản

Freelancer không viết code để chạy 1 lần. Bạn viết code để tích hợp vào hệ thống, tái sử dụng và dễ bảo trì. Chúng ta sẽ nâng cấp code bằng Type HintingGenerator (Tiết kiệm RAM cực đỉnh).

2.1. Tư duy Generator (Yield)

Thay vì tạo ra một list chứa 1 triệu số (ngốn RAM), chúng ta dùng yield để “nhả” ra từng số khi cần. Đây là kỹ thuật “Lazy Evaluation”.

2.2. Mã nguồn chuẩn Python Architect

from typing import Generator, Iterator
from pydantic import validate_call, PositiveInt, ValidationError

class FibonacciService:
    """
    Service xử lý logic Fibonacci chuyên nghiệp.
    Sử dụng Generator để tối ưu bộ nhớ.
    """
    
    @staticmethod
    @validate_call
    def generate_sequence(n: PositiveInt) -> Generator[int, None, None]:
        """
        Sinh ra dãy Fibonacci n phần tử.
        Sử dụng Pydantic để validate đầu vào tự động.
        """
        a, b = 0, 1
        for _ in range(n):
            yield a
            a, b = b, a + b

    @staticmethod
    def get_list(n: int) -> list[int]:
        """Wrapper nếu client thực sự cần trả về List"""
        try:
            # Ép kiểu generator về list
            return list(FibonacciService.generate_sequence(n))
        except ValidationError as e:
            print(f"Lỗi dữ liệu đầu vào: {e}")
            return []

# --- Main Execution Block ---
if __name__ == "__main__":
    # Giả lập tình huống input từ API
    user_input = 10 
    
    print(f"--- Dãy Fibonacci ({user_input} số) ---")
    
    # Cách dùng tối ưu cho bộ nhớ (duyệt từng phần tử)
    fib_gen = FibonacciService.generate_sequence(user_input)
    for num in fib_gen:
        print(num, end=" -> ")
    print("END")

Điểm nhấn kỹ thuật:

  • @validate_call (Pydantic): Tự động kiểm tra n phải là số nguyên dương. Freelancer không cần viết if n < 0 thủ công nữa.

  • yield: Giúp hàm có thể chạy với n = 1,000,000 mà không gây crash bộ nhớ máy tính khách hàng.


3. Cấp độ 3:

Ở cấp độ này, chúng ta không chạy script trên terminal nữa. Chúng ta biến nó thành một High-Performance API có thể chịu tải cao, cache kết quả và đóng gói Docker.

3.1. Tối ưu hóa: Tại sao Generator lại quan trọng?

Tiêu chí Dùng List (Cổ điển) Dùng Generator (Hiện đại)
Bộ nhớ (RAM) Tăng theo n (O(n)) Hằng số (O(1))
Tốc độ khởi động Chậm (Phải tính hết mới trả về) Cực nhanh (Tính số nào trả số đó)
Khả năng Scaling Kém (Dễ Crash với n lớn) Tuyệt vời

3.2. Triển khai FastAPI với Caching (Redis) & Docker

Dưới đây là cấu trúc của một Microservice thực thụ.

File: main.py

from fastapi import FastAPI, HTTPException, Query
from functools import lru_cache
import uvicorn
import time

app = FastAPI(title="Fibonacci High-Performance API", version="2026.1.0")

# 1. Sử dụng Memoization cho thuật toán đệ quy (nếu cần tìm số thứ n)
# lru_cache giúp lưu kết quả đã tính vào RAM, tránh tính lại.
@lru_cache(maxsize=1024)
def fibonacci_nth(n: int) -> int:
    if n < 2:
        return n
    return fibonacci_nth(n-1) + fibonacci_nth(n-2)

# 2. API Endpoint trả về dãy số (Streaming Response pattern)
@app.get("/api/fibonacci/sequence")
async def get_fibonacci_sequence(
    n: int = Query(..., gt=0, le=10000, description="Số lượng phần tử")
):
    """
    API trả về dãy Fibonacci. Giới hạn n=10000 để bảo vệ server.
    """
    start_time = time.perf_counter()
    
    # Logic Generator tái sử dụng
    def gen_fib():
        a, b = 0, 1
        for _ in range(n):
            yield a
            a, b = b, a + b
            
    result = list(gen_fib())
    process_time = time.perf_counter() - start_time
    
    return {
        "metadata": {
            "count": n,
            "execution_time_seconds": f"{process_time:.6f}",
            "algorithm": "Iterative Generator"
        },
        "data": result
    }

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

File: Dockerfile (Để deploy lên Cloud)

Dockerfile

# Sử dụng Python 3.11-slim để image nhẹ nhất
FROM python:3.11-slim

WORKDIR /app

# Cài đặt thư viện cần thiết
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Expose port
EXPOSE 8000

# Chạy app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

3.3. Xử lý “Big Integer”

Trong Python, số nguyên có độ lớn tùy ý (arbitrary-precision). Bạn có thể tính Fibonacci thứ 10,000 với hàng ngàn chữ số mà không bị tràn số (Overflow) như C++ hay Java. Đây là lợi thế tuyệt đối của Python trong Fintech và Scientific Computing.


4. FAQ – Câu hỏi thường gặp 

Dãy Fibonacci - Bài Tập Python cơ bản
Dãy Fibonacci – Bài Tập Python cơ bản

Hỏi: Tại sao dùng đệ quy (recursion) để tính Fibonacci lại chậm?

  • Đáp: Đệ quy ngây thơ tính lặp lại các giá trị con nhiều lần (Ví dụ: F(5) tính F(3) hai lần). Độ phức tạp là O(2^n). Dùng Memoization hoặc vòng lặp sẽ đưa về O(n).

Hỏi: Python xử lý số Fibonacci cực lớn (ví dụ thứ 1000) như thế nào?

  • Đáp: Python tự động chuyển sang chế độ “bignum”, sử dụng mảng bộ nhớ động để lưu số, nên không bị giới hạn 64-bit như C/Java.

Hỏi: yield trong Python có tác dụng gì khi in dãy Fibonacci?

  • Đáp: yield biến hàm thành Generator, chỉ lưu giá trị hiện tại vào RAM, giúp tiết kiệm bộ nhớ khi n rất lớn.

Hỏi: Làm sao để tìm số Fibonacci thứ n trong thời gian O(log n)?

  • Đáp: Sử dụng phương pháp nhân ma trận (Matrix Exponentiation) hoặc công thức Fast Doubling.

Hỏi: Dãy Fibonacci ứng dụng thực tế vào đâu?

  • Đáp: Phân tích kỹ thuật chứng khoán (Fibonacci Retracement), Lập kế hoạch Agile (Scrum Poker), và nén dữ liệu.

Hỏi: Có nên dùng công thức Binet (căn bậc 2) để tính Fibonacci không?

  • Đáp: Chỉ tốt với n nhỏ. Với n lớn, sai số dấu phẩy động (float precision) sẽ làm kết quả không chính xác.

Hỏi: Thư viện nào tốt nhất để validate đầu vào cho bài toán này?

  • Đáp: Pydantic là tiêu chuẩn vàng hiện nay nhờ cú pháp dễ đọc và hiệu năng cao.

Hỏi: Sự khác nhau giữa returnprint trong bài tập này?

  • Đáp: print chỉ hiển thị ra màn hình (dành cho người dùng cuối). return trả về dữ liệu để các hàm khác hoặc hệ thống khác sử dụng tiếp. Luôn ưu tiên return.

Hỏi: Làm sao để cache kết quả Fibonacci API?

  • Đáp: Dùng functools.lru_cache (in-memory) cho quy mô nhỏ hoặc Redis cho hệ thống phân tán.

Các khóa học liên quan: 

Một số sản phẩm từ Python:

Một số sách lập trình Python bạn hãy tham khảo

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *