Buổi 10: Các thuật toán trên dãy

Hôm nay em sẽ học

  1. Tự viết thuật toán tìm lớn nhất / nhỏ nhất và vị trí
  2. Kỹ thuật biến cờ để kiểm tra "mọi phần tử đều …"
  3. Duyệt mọi cặp phần tử
  4. Tìm đoạn liên tiếp dài nhất

Bấm vào slide rồi dùng phím ← → để chuyển, phím F để xem toàn màn hình.

Mở toàn màn hình

1. Kiến thức chính

Tìm lớn nhất và vị trí

mx = a[0]               # KHÔNG khởi tạo mx = 0 (sai khi dãy toàn số âm)
vt = 0
for i in range(1, n):
    if a[i] > mx:
        mx = a[i]
        vt = i
print(mx, vt + 1)       # vị trí đánh số từ 1

Hàm có sẵn được dùng khi đi thi: max(a), min(a), sum(a), a.count(x), a.index(x).

Biến cờ – kiểm tra "mọi phần tử đều …"

tang = True                    # 1. giả sử dãy tăng
for i in range(1, n):
    if a[i] <= a[i - 1]:       # 2. tìm phản ví dụ
        tang = False           # 3. hạ cờ
        break

Duyệt mọi cặp (i < j)

for i in range(n):
    for j in range(i + 1, n):  # j bắt đầu từ i + 1: mỗi cặp xét một lần
        ...

Có khoảng n² ÷ 2 cặp: n = 1000 thì kịp, n = 10⁵ thì không kịp.

Đoạn liên tiếp dài nhất

best = hien_tai = 1
for i in range(1, n):
    if a[i] > a[i - 1]:
        hien_tai += 1          # bậc thang tiếp tục
    else:
        hien_tai = 1           # bắt đầu lại
    best = max(best, hien_tai)

Chỉ duyệt dãy một lần nên chạy nhanh kể cả khi n = 10⁵.

2. Ghi nhớ và lỗi thường gặp

LỗiHậu quả
Khởi tạo mx = 0sai khi dãy toàn số âm
So sánh a[i] với a[i - 1] khi i = 0a[-1] là phần tử cuối – kết quả sai mà không báo lỗi
Quên cập nhật best ở phần tử cuốisai khi đoạn dài nhất nằm ở cuối dãy
Duyệt cặp khi n = 10⁵quá thời gian

3. Câu hỏi tự kiểm tra

  1. Vì sao khởi tạo mx = a[0] tốt hơn mx = 0?
  2. Với n = 5, hai vòng lặp for i in range(n) và for j in range(i + 1, n) xét tất cả bao nhiêu cặp?
  3. Trong dãy 4 4 4, đoạn tăng chặt liên tiếp dài nhất có độ dài bao nhiêu?

4. Bài tập về nhà

Định dạng input chung (trừ khi ghi khác): dòng 1 là n (1 ≤ n ≤ 10⁵), dòng 2 là n số nguyên (|aᵢ| ≤ 10⁹).

Bài 1 ★★ – DEMDINH

Phần tử aᵢ (không phải đầu dãy, không phải cuối dãy) là đỉnh nếu nó lớn hơn cả hai phần tử kề bên.

Output: số đỉnh của dãy.

InputOutput
7
1 3 2 5 4 4 6
2

Bài 2 ★★ – DOANBANG

Output: độ dài đoạn dài nhất gồm các phần tử bằng nhau đứng liên tiếp.

InputOutput
8
1 1 2 2 2 3 2 2
3

Bài 3 ★★ – CAPSOCONG

Dãy là cấp số cộng nếu hiệu hai số liên tiếp luôn bằng nhau (ví dụ 2 5 8 11).

Output: YES hoặc NO.

InputOutput
4
2 5 8 11
YES
3
1 2 4
NO

Bài 4 ★★★ (thử thách) – LAINHAT

aᵢ là giá một món hàng vào ngày thứ i. Em mua vào một ngày và bán ra vào một ngày sau đó. Tìm tiền lãi lớn nhất (có thể âm nếu ngày nào cũng lỗ).

Input: như trên với n ≥ 2. Output: lãi lớn nhất = max(aⱼ − aᵢ) với i < j.

InputOutput
6
7 1 5 3 6 4
5
3
5 4 1
-1
Gợi ý: n = 10⁵ nên không duyệt mọi cặp được. Khi duyệt đến ngày j, em chỉ cần biết giá thấp nhất trước ngày j.
Cách nộp bài: mỗi bài một file .py đặt tên theo tên bài. Chạy thử với tất cả ví dụ trước khi nộp!

Chưa mở đáp án

Đáp án sẽ được mở sau khi các em nộp bài tập về nhà.

Chưa mở đáp án

Đáp án sẽ được mở sau khi các em nộp bài tập về nhà.

Zalo