Cho một số nguyên không âm n.
Hãy tính tổng các chữ số của n.
Ví dụ: n = 12345
Tổng chữ số = 1 + 2 + 3 + 4 + 5 = 15.
Ý tưởng: Dùng phép chia lấy dư cho 10 để lấy chữ số cuối cùng, sau đó chia nguyên cho 10 để bỏ chữ số cuối cùng.
long long tongchuso(long long n)
{
long long kq = 0;
while (n > 0)
{
kq += n % 10;
n /= 10;
}
return kq;
}
Đặc điểm:
Ý tưởng: Khi tính tổng chữ số của một số lần đầu, lưu kết quả vào mảng. Nếu cần tính lại số đó, lấy kết quả đã lưu thay vì tính lại từ đầu.
const int MAXN = 1000000;
long long tong[MAXN + 1];
bool daTinh[MAXN + 1];
long long tongchuso(long long s)
{
if (s < 0 || s > MAXN)
return -1;
if (daTinh[s])
return tong[s];
long long n = s;
long long kq = 0;
while (n > 0)
{
kq += n % 10;
n /= 10;
}
tong[s] = kq;
daTinh[s] = true;
return tong[s];
}
Đặc điểm:
Ý tưởng: Tính trước tổng chữ số của tất cả các số từ 0 đến MAXN. Dựa vào kết quả của số đã bỏ đi chữ số cuối cùng để tính số hiện tại. Công thức:
tong[i] = tong[i / 10] + i % 10;Ví dụ:
Chương trình hoàn chỉnh:
#include <iostream>
using namespace std;
const int MAXN = 1000000;
long long tong[MAXN + 1];
int main()
{
for (int i = 1; i <= MAXN; i++)
{
tong[i] = tong[i / 10] + i % 10;
}
cout << tong[12345] << endl;
cout << tong[6789] << endl;
return 0;
}
Đặc điểm:
| Tiêu chí | While | Memoization | Quy hoạch động |
|---|---|---|---|
| Lần đầu tính | O(log n) | O(log n) | Tính trước O(MAXN) |
| Tính lại số cũ | O(log n) | O(1) | O(1) |
| Bộ nhớ | O(1) | O(MAXN) | O(MAXN) |
| Điểm mạnh | Đơn giản | Không tính lại số cũ | Trả lời truy vấn nhanh |
Lưu ý: Với số rất lớn như 10^12, không thể dùng mảng có kích thước 1.000.001 để lưu kết quả cho mọi số. Khi đó, vòng lặp while thường là lựa chọn phù hợp nếu không có thêm yêu cầu đặc biệt.
CÁC THUẬT TOÁN TỐI ƯU TÍNH TỔNG CHỮ SỐ TRONG C++