Bài 11.4: Các dạng bài tập mảng 1 chiều cơ bản trong C++

Chào mừng các bạn quay trở lại với series học lập trình C++!

Sau khi đã tìm hiểu về khái niệm mảng 1 chiều (one-dimensional array) trong bài trước, hôm nay chúng ta sẽ cùng nhau đi sâu vào thực hành qua các dạng bài tập cơ bản và phổ biến nhất. Việc nắm vững các thao tác cơ bản với mảng là cực kỳ quan trọng, vì mảng là cấu trúc dữ liệu nền tảng, xuất hiện rất nhiều trong các bài toán lập trình thực tế.

Chúng ta sẽ lần lượt khám phá các dạng bài tập sau:

  1. Nhập và xuất mảng
  2. Tính tổng và trung bình cộng các phần tử
  3. Tìm kiếm phần tử nhỏ nhất, lớn nhất (và vị trí của chúng)
  4. Tìm kiếm một giá trị cụ thể trong mảng
  5. Đếm số lượng phần tử thỏa mãn một điều kiện

Bắt tay vào thôi nào!

1. Nhập và xuất mảng

Đây là thao tác cơ bản nhất khi làm việc với mảng. Chúng ta cần biết cách đưa dữ liệu vào mảng từ bàn phím (nhập) và hiển thị dữ liệu của mảng ra màn hình (xuất).

Để làm điều này, chúng ta thường sử dụng vòng lặp for để duyệt qua từng phần tử của mảng thông qua chỉ số (index) của chúng.

Mảng 1 chiều trong C++ có các phần tử được đánh chỉ số từ 0 đến kích thước - 1.

Ví dụ:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int N;
    cout << "Nhap so luong phan tu cua mang: ";
    cin >> N;

    vector<int> A(N);

    // NHAP MANG
    cout << "Nhap cac phan tu cua mang:\n";
    for (int i = 0; i < N; ++i) {
        cout << "A[" << i << "]: ";
        cin >> A[i];
    }

    // XUAT MANG
    cout << "\nMang vua nhap la:\n";
    for (int i = 0; i < N; ++i) {
        cout << A[i] << (i == N - 1 ? "" : " ");
    }
    cout << endl;

    return 0;
}

Output ví dụ:

Nhap so luong phan tu cua mang: 3
Nhap cac phan tu cua mang:
A[0]: 10
A[1]: 20
A[2]: 30

Mang vua nhap la:
10 20 30

2. Tính tổng và trung bình cộng các phần tử

Đây là một bài tập kinh điển sử dụng vòng lặp để xử lý dữ liệu trong mảng. Để tính tổng, chúng ta cần một biến tích lũy (accumulator), khởi tạo bằng 0, và cộng dồn giá trị của từng phần tử vào biến này khi duyệt mảng. Trung bình cộng đơn giản là tổng chia cho số lượng phần tử.

Ví dụ:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> A = {10, 20, 30, 40, 50};
    int N = A.size();

    if (N == 0) {
        cout << "Mang rong, khong the tinh tong hoac TBC.\n";
        return 0;
    }

    long long tong = 0;
    for (int i = 0; i < N; ++i) {
        tong += A[i];
    }

    double TBC = static_cast<double>(tong) / N;

    cout << "Mang da cho: ";
    for (int x : A) { // Dung for-each de in mang
        cout << x << " ";
    }
    cout << endl;

    cout << "Tong cac phan tu: " << tong << endl;
    cout << "Trung binh cong: " << TBC << endl;

    return 0;
}

Output ví dụ:

Mang da cho: 10 20 30 40 50 
Tong cac phan tu: 150
Trung binh cong: 30

3. Tìm phần tử nhỏ nhất, lớn nhất

Bài toán này yêu cầu tìm giá trị nhỏ nhất (min) và lớn nhất (max) trong mảng. Cách tiếp cận phổ biến là giả sử phần tử đầu tiên là min và max ban đầu, sau đó duyệt qua các phần tử còn lại và cập nhật min/max nếu tìm thấy giá trị nhỏ hơn hoặc lớn hơn.

Ví dụ:

#include <iostream>
#include <vector>
#include <limits> // Dung numeric_limits de khoi tao min/max

using namespace std;

int main() {
    vector<int> A = {5, 12, 8, 25, 3, 18};
    int N = A.size();

    if (N == 0) {
        cout << "Mang rong, khong tim duoc min/max.\n";
        return 0;
    }

    int minGiaTri = A[0];
    int maxGiaTri = A[0];

    int minViTri = 0;
    int maxViTri = 0;

    for (int i = 1; i < N; ++i) {
        if (A[i] < minGiaTri) {
            minGiaTri = A[i];
            minViTri = i;
        }
        if (A[i] > maxGiaTri) {
            maxGiaTri = A[i];
            maxViTri = i;
        }
    }

    cout << "Mang da cho: ";
    for (int x : A) {
        cout << x << " ";
    }
    cout << endl;

    cout << "Phan tu nho nhat: " << minGiaTri << " (tai chi so " << minViTri << ")" << endl;
    cout << "Phan tu lon nhat: " << maxGiaTri << " (tai chi so " << maxViTri << ")" << endl;

    return 0;
}

Output ví dụ:

Mang da cho: 5 12 8 25 3 18 
Phan tu nho nhat: 3 (tai chi so 4)
Phan tu lon nhat: 25 (tai chi so 3)

4. Tìm kiếm một giá trị cụ thể

Bài toán này là kiểm tra xem một giá trị target có tồn tại trong mảng hay không. Nếu có, chúng ta có thể muốn biết nó xuất hiện ở những vị trí (chỉ số) nào. Cách đơn giản nhất là duyệt qua từng phần tử và so sánh với giá trị target.

Ví dụ:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> A = {10, 5, 20, 5, 30, 5};
    int N = A.size();
    int timGT = 5;

    cout << "Mang da cho: ";
    for (int x : A) {
        cout << x << " ";
    }
    cout << endl;

    cout << "Tim kiem gia tri: " << timGT << endl;

    bool coTimThay = false;
    for (int i = 0; i < N; ++i) {
        if (A[i] == timGT) {
            cout << "Tim thay gia tri " << timGT << " tai chi so: " << i << endl;
            coTimThay = true;
        }
    }

    if (!coTimThay) {
        cout << "Khong tim thay gia tri " << timGT << " trong mang.\n";
    }

    return 0;
}

Output ví dụ:

Mang da cho: 10 5 20 5 30 5 
Tim kiem gia tri: 5
Tim thay gia tri 5 tai chi so: 1
Tim thay gia tri 5 tai chi so: 3
Tim thay gia tri 5 tai chi so: 5

5. Đếm số lượng phần tử thỏa mãn điều kiện

Bài toán này yêu cầu đếm có bao nhiêu phần tử trong mảng thỏa mãn một điều kiện nhất định (ví dụ: số chẵn, số lẻ, số dương, số âm, số lớn hơn 100, v.v.). Cách làm tương tự như tính tổng, nhưng thay vì cộng dồn giá trị, chúng ta tăng một biến đếm mỗi khi điều kiện được thỏa mãn.

Ví dụ: Đếm số lượng phần tử chẵn trong mảng.

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> A = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int N = A.size();

    cout << "Mang da cho: ";
    for (int x : A) {
        cout << x << " ";
    }
    cout << endl;

    int soChan = 0;

    for (int i = 0; i < N; ++i) {
        if (A[i] % 2 == 0) {
            soChan++;
        }
    }

    cout << "So luong phan tu chan trong mang: " << soChan << endl;

    return 0;
}

Output ví dụ:

Mang da cho: 1 2 3 4 5 6 7 8 9 10 
So luong phan tu chan trong mang: 5

Bài tập ví dụ: C++ Bài 7.A4: Tính tổng mảng

Cho một dãy số \(a\) có \(N\) phần từ \(a_1, a_2, a_3,...a_n\).

Hãy làm theo các yêu cầu sau đây:

  • Tính tổng các phần tử trong dãy số \(a\).
  • Tính giá trị trung bình các phần tử trong dãy số \(a\), lấy phần nguyên.
  • Tìm giá trị lớn nhất trong dãy số \(a\).
  • Tìm giá trị nhỏ nhất trong dãy số \(a\).

INPUT FORMAT

Dòng đầu tiên chứa số nguyên \(N\) ( \(N \leq 10^6\)).

Dòng thứ hai chứa \(N\) số nguyên, mỗi số các nhau một dấu cách \((a_i < 10^9)\)

OUTPUT FORMAT

Dòng đầu tiên in ra tổng các phần tử trong dãy \(a\).

Dòng thứ hai in ra giá trị trung bình các phần tử trong dãy số \(a\), lấy phần nguyên.

Dòng thứ ba in ra giá trị lớn nhất trong dãy số \(a\).

Dòng thứ tư in ra giá trị nhỏ nhất trong dãy số \(a\).

Ví dụ 1:

Input
3
1 2 3
Ouput
6
2
3
1

Ví dụ 2:

Input
5
5 3 1 6 3
Ouput
18
3
6
1
Giải thích ví dụ mẫu:
  • Ví dụ 1:

    • Tổng các phần tử: 6
    • Giá trị trung bình (làm tròn xuống): 2
    • Giá trị lớn nhất: 3
    • Giá trị nhỏ nhất: 1
  • Ví dụ 2:

    • Tổng các phần tử: 18
    • Giá trị trung bình (làm tròn xuống): 3
    • Giá trị lớn nhất: 6
    • Giá trị nhỏ nhất: 1

Phân tích và hướng tiếp cận:

  1. Đọc dữ liệu: Bạn cần đọc số nguyên N đầu tiên, sau đó đọc N số nguyên tiếp theo.
  2. Tính toán:
    • Tổng: Bạn cần một biến để lưu tổng. Khi đọc từng số, bạn cộng nó vào biến tổng. Chú ý đến kiểu dữ liệu của biến tổng vì N có thể lên đến 10^6 và mỗi số có thể gần 10^9, tổng có thể rất lớn. Kiểu dữ liệu long long trong C++ là phù hợp để lưu trữ tổng này.
    • Trung bình (nguyên): Sau khi có tổng, bạn chia tổng cho N. Vì yêu cầu lấy phần nguyên, phép chia số nguyên (/) trong C++ sẽ tự động thực hiện điều này (với số dương). Kết quả trung bình cũng nên dùng long long để đảm bảo tính toán chính xác trước khi in ra.
    • Giá trị lớn nhất: Bạn cần một biến để lưu giá trị lớn nhất tìm được cho đến thời điểm hiện tại. Khởi tạo biến này với giá trị của phần tử đầu tiên hoặc một giá trị rất nhỏ. Sau đó, khi đọc từng số tiếp theo, so sánh nó với giá trị lớn nhất đang có và cập nhật nếu số mới lớn hơn.
    • Giá trị nhỏ nhất: Tương tự như giá trị lớn nhất, bạn cần một biến lưu giá trị nhỏ nhất. Khởi tạo nó với giá trị của phần tử đầu tiên hoặc một giá trị rất lớn. So sánh từng số mới đọc với giá trị nhỏ nhất đang có và cập nhật nếu số mới nhỏ hơn.
  3. Hiệu quả:N có thể lớn (10^6), bạn nên xử lý các số khi đọc vào thay vì lưu toàn bộ dãy số vào một mảng (vector) nếu bộ nhớ là vấn đề (mặc dù với 10^6 số int thì vẫn thường chấp nhận được). Tuy nhiên, cách xử lý từng số khi đọc vào là hiệu quả nhất về bộ nhớ và đủ nhanh cho yêu cầu này (một lần duyệt qua dữ liệu).
  4. Sử dụng std: Bạn có thể sử dụng các hàm có sẵn trong thư viện chuẩn C++ như maxmin để tìm giá trị lớn nhất/nhỏ nhất một cách ngắn gọn.

Các bước thực hiện (Hướng dẫn):

  1. Bao gồm các thư viện cần thiết: iostream để nhập/xuất và algorithm (cho max, min).
  2. Đọc giá trị N.
  3. Khai báo các biến cần thiết:
    • Một biến kiểu long long để tính tổng, khởi tạo bằng 0.
    • Hai biến kiểu int để lưu giá trị lớn nhất và nhỏ nhất.
    • Một biến kiểu int để đọc từng số trong dãy.
  4. Xử lý số đầu tiên: Đọc số đầu tiên của dãy. Dùng số này để khởi tạo giá trị ban đầu cho biến lớn nhất và nhỏ nhất. Cộng số này vào tổng.
  5. Vòng lặp: Dùng vòng lặp để đọc và xử lý N-1 số còn lại của dãy.
    • Trong mỗi lần lặp, đọc số tiếp theo.
    • Cộng số vừa đọc vào biến tổng.
    • Sử dụng max để cập nhật biến lớn nhất: so sánh biến lớn nhất hiện tại với số vừa đọc và gán kết quả lớn hơn vào biến lớn nhất.
    • Sử dụng min để cập nhật biến nhỏ nhất: so sánh biến nhỏ nhất hiện tại với số vừa đọc và gán kết quả nhỏ hơn vào biến nhỏ nhất.
  6. Tính trung bình: Sau vòng lặp, tính giá trị trung bình nguyên bằng cách chia tổng cho N (sử dụng phép chia /). Lưu ý: Nint, tổng là long long. Phép chia giữa long longint sẽ tự động trả về long long.
  7. In kết quả: In lần lượt tổng, trung bình (nguyên), giá trị lớn nhất và giá trị nhỏ nhất trên các dòng riêng biệt theo đúng định dạng yêu cầu.

Gợi ý về code (Không phải code hoàn chỉnh):

#include <iostream>
#include <algorithm>

using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N;
    cin >> N;

    long long tong = 0;
    int maxV, minV;
    int x;

    cin >> x; // Doc so dau tien
    tong += x;
    maxV = x;
    minV = x;

    for (int i = 1; i < N; ++i) { // Doc N-1 so con lai
        cin >> x;
        tong += x;
        maxV = max(maxV, x);
        minV = min(minV, x);
    }

    long long TBC = tong / N;

    cout << tong << endl;
    cout << TBC << endl;
    cout << maxV << endl;
    cout << minV << endl;

    return 0;
}

Output ví dụ 1: Input:

3
1 2 3

Output:

6
2
3
1

Output ví dụ 2: Input:

5
5 3 1 6 3

Output:

18
3
6
1

Làm thêm nhiều bài tập miễn phí tại đây

Comments

There are no comments at the moment.