Tuyển sinh 🎓 Mình nhận đào tạo lập trình giải thuật thi đấu: thi vào lớp 10 chuyên tin · thi học sinh giỏi tin học cấp tỉnh/thành · thi vào đội tuyển quốc gia · Olympic tin học sinh viên / ICPC · phỏng vấn thuật toán. Bấm vào đây để xem thông tin khóa học → Xem khóa học

Đọc số điện thoại

Đọc số điện thoại
Nguồn: CLUE OJ Độ khó: Dễ Nhập xuất Xâu ký tự

Đề bài

Điện thoại của Lan có tính năng đọc to số của người đang gọi đến: nó đọc từng chữ số một. Ví dụ số $0942250787$ sẽ được đọc là 0 9 4 2 2 5 0 7 8 7.

Cho một số điện thoại gồm đúng $10$ chữ số, hãy in ra lần lượt các chữ số của nó, mỗi chữ số cách nhau một dấu cách.

Dữ liệu vào: Một dòng chứa số điện thoại $N$ gồm đúng $10$ chữ số (có thể bắt đầu bằng chữ số $0$).

Kết quả: In ra $10$ chữ số của $N$ theo đúng thứ tự, cách nhau bởi một dấu cách.

Giới hạn:

  • $N$ có đúng $10$ chữ số, các chữ số từ $0$ đến $9$ (kể cả chữ số $0$ ở đầu).

Giới hạn thời gian: 1 giây, bộ nhớ: 256 MB. Dữ liệu nhập từ bàn phím và in ra màn hình.

Ví dụ 1 – input
0167469666
Ví dụ 1 – output
0 1 6 7 4 6 9 6 6 6
Ví dụ 2 – input
0942250787
Ví dụ 2 – output
0 9 4 2 2 5 0 7 8 7

Nguồn: phỏng theo bài "QMOBILE" – vinhdinhcoder.net.

Lời mở đầu

Đề nói "cho một số điện thoại", thế là rất nhiều bạn phản xạ ngay long long n; cin >> n;. Nhưng số điện thoại không phải là "số" để làm toán – nó là một dãy ký tự chữ số, và chữ số 0 ở đầu là một phần quan trọng của nó. Bài này dạy đúng một điều: chọn kiểu dữ liệu theo ý nghĩa của dữ liệu. Mình sẽ cho các em xem code bẫy, rồi hai cách làm đúng: đọc xâu, và (cho bạn nào thích) đọc số nhưng tách đúng 10 chữ số.

Dành cho học viên · Ưu tiênNộp bài trên hệ thống CLUE OJ

Link này chỉ học viên đã tham gia tổ chức mới vào được. Học viên nên ưu tiên nộp ở đây vì sẽ được chấm nhanh hơn.

Nộp bài trên CLUE OJ

Lộ trình lời giải, bấm vào từng phần để nhảy tới:

Bộ testBộ test chính thức có gì?

Bộ test có 20 test, bài không chia subtask. Mỗi test là một xâu đúng 10 chữ số. Mình đếm số chữ số 0 ở đầu của từng test:

Số chữ số 0 ở đầu01235910
Số test3913211
  • Có tới 17/20 test bắt đầu bằng chữ số 0 (có test toàn số 0 0000000000, có test chỉ có chữ số cuối khác 0). Chỉ có test 4, 6, 10 là không có số 0 ở đầu.
  • Có 2 test (test 4, 10) có giá trị lớn hơn $2^{31} - 1 = 2\,147\,483\,647$ – nếu đọc bằng int thì tràn.

Ý tưởngSố điện thoại là xâu, không phải số

Khi đọc 0942250787 vào một biến số nguyên, máy chỉ lưu giá trị $942\,250\,787$ – số 0 ở đầu không làm thay đổi giá trị nên bị "nuốt" mất, và máy không còn cách nào biết ban đầu có mấy số 0. Còn đọc vào một xâu (string) thì máy giữ nguyên văn từng ký tự em gõ vào.

Em nhập một số điện thoại 10 chữ số rồi bấm Tiếp để so sánh hai cách đọc:

Ví dụ nhanh:

BẫyĐọc thành số rồi in lại

C++▶ Chạy tay từng dòng codeBẫy: đọc vào long long rồi đổi lại thành xâu – số 0 ở đầu đã mất.
Dữ liệu mẫu:
  1. cin >> n đọc 0942250787 thành giá trị $942\,250\,787$; to_string(n) cho xâu "942250787" chỉ có 9 ký tự → in ra thiếu số 0 đầu.
  2. Test 0000000000 còn tệ hơn: $n = 0$, chỉ in ra đúng một chữ số 0 thay vì mười.
  3. Bản Python int(input()) mắc y hệt lỗi này.

Kết quả chạy thật: bản C++ đúng 3/20 test, sai ở test 1–3, 5, 7–9, 11–20; test đúng chạy lâu nhất 0.00s – chỉ đúng 3 test không có số 0 ở đầu. Bản Python đúng 3/20 test, sai ở test 1–3, 5, 7–9, 11–20; test đúng chạy lâu nhất 0.01s.

Cách 1Đọc xâu, in từng ký tự

Đọc vào string s, rồi duyệt từng ký tự s[i], in kèm một dấu cách.

C++▶ Chạy tay từng dòng codeCách 1: đọc xâu, in từng ký tự.
Dữ liệu mẫu:
  1. cin >> s đọc nguyên văn "từ" 0942250787 – mỗi ký tự là một chữ số, kể cả các số 0 ở đầu.
  2. s[i] có kiểu char nên cout << s[i] in ra đúng ký tự chữ số đó.
  3. Sau chữ số cuối có thừa một dấu cách – trình chấm so sánh theo từng "từ" nên không sao (code đã được chấm thật, xem kết quả).
  4. Python: print(*s) "rải" từng ký tự của xâu làm các tham số của print, và print tự chèn dấu cách giữa chúng.
Không gian$O(10)$
Thời gian$O(10)$

Kết quả chạy thật: bản C++ đúng 20/20 test; test đúng chạy lâu nhất 0.00s. Bản Python đúng 20/20 test; test đúng chạy lâu nhất 0.02s. Full điểm.

Cách 2Vẫn đọc số, nhưng tách đúng 10 chữ số

Thật ra đọc vào số cũng làm được, nếu ta nhớ là số điện thoại luôn có đúng 10 chữ số: cứ lấy n % 10 (chữ số hàng đơn vị) rồi n /= 10, lặp đúng 10 lần. Khi các chữ số "thật" đã hết thì $n = 0$ và n % 10 cho ra chính các số 0 ở đầu! Các chữ số được tách từ phải sang trái nên ta lưu vào mảng d[9], d[8], …, d[0] rồi in theo thứ tự xuôi.

C++▶ Chạy tay từng dòng codeCách 2: đọc long long, tách đúng 10 chữ số bằng % 10 và / 10.
Dữ liệu mẫu:
  1. Vòng lặp chạy cố định 10 lần, không dừng khi $n = 0$ – đó là mấu chốt để giữ số 0 ở đầu.
  2. Phải dùng long long: số điện thoại có thể tới $9\,999\,999\,999 > 2^{31} - 1$. Mình thử đổi thành int: bản int đúng 18/20 test, sai ở test 4, 10; test đúng chạy lâu nhất 0.00s – sai đúng test 4, 10 có giá trị vượt int (khi số quá lớn, cin báo lỗi và gán $n = 2\,147\,483\,647$, nên in ra 2 1 4 7 4 8 3 6 4 7).
Không gian$O(10)$
Thời gian$O(10)$

Kết quả chạy thật: bản C++ đúng 20/20 test; test đúng chạy lâu nhất 0.00s. Bản Python đúng 20/20 test; test đúng chạy lâu nhất 0.02s. Full điểm.

Tổng kếtKết quả chạy thật trên bộ test

CodeNgôn ngữĐúngLâu nhấtGhi chú
Bẫy: đọc thành số rồi in lạiC++3/200.00sSai test 1–3, 5, 7–9, 11–20 (mất số 0 đầu)
Python3/200.01sSai test 1–3, 5, 7–9, 11–20
Cách 1: đọc xâuC++20/200.00sFull điểm
Python20/200.02sFull điểm
Cách 2: số + tách đúng 10 chữ sốC++20/200.00sFull điểm
Python20/200.02sFull điểm
Cách 2 nhưng dùng intC++18/200.00sSai test 4, 10 (vượt int)
Ghi chú của mình: thời gian là thời gian CPU đo trên máy mình (giới hạn 1 giây). Quy tắc nhỏ đáng nhớ: số điện thoại, mã số học sinh, số căn cước, mã bưu chính… tuy toàn chữ số nhưng là mã, không dùng để cộng trừ nhân chia – hãy lưu chúng bằng xâu. Chỉ dùng kiểu số khi em thật sự cần làm toán với nó.
Rất vui khi anh em nào đã đọc đến những dòng cuối cùng này. Anh em đọc chắc cũng mỏi mắt luôn chứ 😅 vậy anh em nghĩ người viết ra hết đống ở trên còn thế nào nữa 🤪. Vậy nên đừng tiếc gì cho mình một lời bình luận hoặc chia sẻ bài viết để động viên mình nè. Chúc anh em học tốt và gặt hái nhiều thành công 😇

Nhận xét