Bài tập mảng bổ trợ (10 bài)
BÀI TẬP
MẢNG BỔ TRỢ — GIẢI CHI TIẾT (Java_Lab_Basic_Ex.pdf)
Bộ 10 bài nhỏ trong tệp PDF 1 trang (bản gốc là ảnh). Mỗi bài đi theo cấu trúc rút gọn: đề → phân tích → code → chạy → kiểm thử → lỗi → câu hỏi, vì đây là bài luyện phản xạ, không phải bài thiết kế lớp.
| # | Bài | Kỹ thuật |
|---|---|---|
| 1 | Nhập tên, in lại | Scanner.nextLine |
| 2 | Số 1–7 → thứ | switch |
| 3 | Phương thức bình phương của 10 | static method |
| 4 | 10 bội số đầu của 5 | for |
| 5 | 10 số nguyên tố đầu | while + hàm nguyên tố |
| 6 | Chẵn / lẻ | if + % |
| 7 | Nguyên âm | switch/equalsIgnoreCase |
| 8 | Đếm cặp bằng nhau liền kề | duyệt i và i+1 |
| 9 | Phần tử không nhỏ hơn mọi số trước | max tiền tố |
| 10 | Ma trận chỉ gồm 0/1 | mảng 2 chiều |
Bài 1 — Nhập tên và in lại
Đề: Write a program to accept a name and display the same.
Phân tích: dùng nextLine() để nhận cả
chuỗi có dấu cách. Cảnh báo: nếu trước đó có nextInt() thì
phải ăn Enter (buổi 2).
// ===== NhapTen.java =====
import java.util.Scanner;
public class NhapTen {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap ten: ");
String ten = sc.nextLine();
System.out.println("Xin chao " + ten);
sc.close();
}
}Chạy:
Nhap ten: Nguyen Van An
Xin chao Nguyen Van An
Kiểm thử: tên rỗng → Xin chao (hợp
lệ); tên 1 từ → đúng. Lỗi: dùng next() →
chỉ nhận Nguyen; quên import →
cannot find symbol. Câu hỏi: khi nào
nextLine trả về chuỗi rỗng? (Ngay sau
nextInt.)
Bài 2 — Số 1–7 → thứ trong tuần
Đề: accept a number between 1 and 7 and return the corresponding day of the week.
Phân tích: so bằng với danh sách rời rạc →
switch; ngoài miền → default.
// ===== ThuTrongTuan.java =====
import java.util.Scanner;
public class ThuTrongTuan {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap so (1-7): ");
int n = sc.nextInt();
switch (n) {
case 1: System.out.println("Monday"); break;
case 2: System.out.println("Tuesday"); break;
case 3: System.out.println("Wednesday"); break;
case 4: System.out.println("Thursday"); break;
case 5: System.out.println("Friday"); break;
case 6: System.out.println("Saturday"); break;
case 7: System.out.println("Sunday"); break;
default: System.out.println("Khong hop le");
}
sc.close();
}
}Bảng kiểm thử: 1 → Monday; 7 → Sunday; 0 → Không hợp
lệ; 8 → Không hợp lệ. Lỗi: thiếu break →
in nhiều thứ liền nhau. Câu hỏi: vì sao
default phải đặt cuối nhưng không cần
break? (Nó là nhánh cuối, không rơi xuống đâu nữa.)
Bài 3 — Phương thức tính bình phương của 10
Đề: Write a program that calls a method to find the square of 10.
Phân tích: tách phép tính ra phương thức riêng — bài học về "chia để trị", không phải chỉ để có kết quả.
// ===== BinhPhuong.java =====
public class BinhPhuong {
public static int binhPhuong(int x) {
return x * x;
}
public static void main(String[] args) {
int kq = binhPhuong(10);
System.out.println("Binh phuong cua 10 la: " + kq);
}
}Chạy:
Binh phuong cua 10 la: 100
Kiểm thử: binhPhuong(0) = 0;
binhPhuong(-3) = 9; binhPhuong(46341) tràn
int (âm) — dùng long nếu cần.
Lỗi:
public void binhPhuong(int x) { return x*x; } →
unexpected return value; gọi binhPhuong()
thiếu tham số →
method binhPhuong cannot be applied to given types.
Câu hỏi: vì sao binhPhuong phải
static khi gọi từ main? (main là static, không
có object.)
Bài 4 — 10 bội số đầu của 5
Đề: Write a program to display the first 10 multiples of 5.
Phân tích: biết trước số lần (10) →
for. Bội số thứ i là 5*i.
// ===== BoiSoCua5.java =====
public class BoiSoCua5 {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
System.out.print(5 * i + " ");
}
System.out.println();
}
}Chạy:
5 10 15 20 25 30 35 40 45 50
Bảng kiểm thử: 10 phần tử, phần tử cuối
50, tổng 275. Lỗi:
for (int i = 0; i < 10; i++) mà in 5*i →
bắt đầu bằng 0 và kết thúc 45 (vẫn 10 số nhưng
sai đề "bội số đầu"). Câu hỏi: nếu đề là "các bội số
của 5 nhỏ hơn 100" thì điều kiện vòng lặp đổi thành gì?
Bài 5 — 10 số nguyên tố đầu tiên
Đề: Write a program to list the first 10 prime numbers.
Phân tích: không biết trước số cần
kiểm tra → while đếm đến 10; dùng hàm
laNguyenTo.
// ===== MuoiNguyenTo.java =====
public class MuoiNguyenTo {
public static boolean laNguyenTo(int n) {
if (n < 2) return false;
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) return false;
}
return true;
}
public static void main(String[] args) {
int dem = 0;
int so = 2;
while (dem < 10) {
if (laNguyenTo(so)) {
System.out.print(so + " ");
dem++;
}
so++;
}
System.out.println();
}
}Chạy:
2 3 5 7 11 13 17 19 23 29
Trace 4 lượt đầu: so=2 → nguyên tố,
dem=1; 3 → dem=2; 4
→ bỏ; 5 → dem=3. Lỗi: dùng
for (so = 2; so < 30; ...) → in 10 số nhưng "may mắn"
đúng; nếu đổi 10 thành 15 sẽ thiếu. Phải đếm theo dem.
Câu hỏi: vì sao dùng while mà không
for? (Số lần lặp chưa biết trước.)
Bài 6 — Chẵn hay lẻ
Đề: accept a number and display whether it is odd or even.
// ===== ChanLe.java =====
import java.util.Scanner;
public class ChanLe {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap so: ");
int n = sc.nextInt();
if (n % 2 == 0) System.out.println(n + " la so chan");
else System.out.println(n + " la so le");
sc.close();
}
}Chạy: 7 → 7 la so le.
Kiểm thử: 0 → chẵn; -4 → chẵn
(-4 % 2 == 0); -3 → lẻ. Lỗi:
n % 2 == 1 cho số âm → sai (-3 % 2 = -1). Luôn
so với 0. Câu hỏi: vì sao %
với số âm lại trả -1? (Java giữ dấu của số bị chia.)
Bài 7 — Kiểm tra nguyên âm
Đề: accept a character; nếu là
a, e, i, o, u in You have input, Vowel, ngược
lại This is not a Vowel.
Phân tích: nhập cả chữ hoa; chỉ lấy ký tự đầu nếu người dùng gõ nhiều ký tự.
// ===== NguyenAm.java =====
import java.util.Scanner;
public class NguyenAm {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap mot ky tu: ");
String s = sc.next();
char c = Character.toLowerCase(s.charAt(0));
switch (c) {
case 'a': case 'e': case 'i': case 'o': case 'u':
System.out.println("You have input, Vowel");
break;
default:
System.out.println("This is not a Vowel");
}
sc.close();
}
}Chạy: e →
You have input, Vowel; B →
This is not a Vowel. Trace:
"B" → toLowerCase('B') = 'b' → không khớp case
nào → default. Lỗi:
sc.next().charAt(0) khi người dùng chỉ gõ Enter →
StringIndexOutOfBoundsException; dùng == so
char thì được (char là nguyên thủy), nhưng
so String thì không. Câu hỏi: vì sao dùng
switch gộp case thay vì 5 câu if?
Bài 8 — Đếm cặp số bằng nhau liền kề
Đề (tiếng Việt): Viết chương trình đếm các cặp số bằng nhau liên tiếp trong dãy số nguyên.
Phân tích: duyệt i từ 0 đến
n-2, so a[i] với a[i+1].
Bắt buộc i < n-1, nếu không sẽ truy cập
a[n].
// ===== CapBangNhau.java =====
import java.util.Scanner;
public class CapBangNhau {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap n: ");
int n = sc.nextInt();
if (n < 2) {
System.out.println("Can it nhat 2 phan tu");
sc.close();
return;
}
int[] a = new int[n];
for (int i = 0; i < n; i++) {
System.out.print("a[" + i + "] = ");
a[i] = sc.nextInt();
}
int dem = 0;
for (int i = 0; i < n - 1; i++) {
if (a[i] == a[i + 1]) dem++;
}
System.out.println("So cap bang nhau lien ke: " + dem);
sc.close();
}
}Chạy với 1 1 2 2 2 3 4 4:
So cap bang nhau lien ke: 4
Trace:
i |
a[i] |
a[i+1] |
Bằng? | dem |
|---|---|---|---|---|
| 0 | 1 | 1 | có | 1 |
| 1 | 1 | 2 | không | 1 |
| 2 | 2 | 2 | có | 2 |
| 3 | 2 | 2 | có | 3 |
| 4 | 2 | 3 | không | 3 |
| 5 | 3 | 4 | không | 3 |
| 6 | 4 | 4 | có | 4 |
Kiểm thử: {5,5} → 1;
{1,2,3} → 0; n=1 → báo cần ít nhất 2.
Lỗi: i < n →
ArrayIndexOutOfBoundsException; đếm "số phần tử trùng nhau"
thay vì "số cặp" → sai bản chất. Câu hỏi: dãy
2 2 2 có mấy cặp? (2 cặp, không phải 3.)
Bài 9 — Phần tử không nhỏ hơn mọi số đứng trước
Đề: Cho dãy n số nguyên dương
(2 ≤ n ≤ 50). Liệt kê các phần tử không nhỏ
hơn mọi phần tử đứng trước nó (tính cả phần tử đầu).
Phân tích: giữ maxTruoc = max của đoạn
đã duyệt; phần tử hiện tại ≥ maxTruoc thì in và cập
nhật.
// ===== KhongNhoHonTruoc.java =====
import java.util.Scanner;
public class KhongNhoHonTruoc {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap n (2-50): ");
int n = sc.nextInt();
if (n < 2 || n > 50) {
System.out.println("n phai trong 2..50");
sc.close();
return;
}
int[] a = new int[n];
for (int i = 0; i < n; i++) {
System.out.print("a[" + i + "] = ");
a[i] = sc.nextInt();
}
System.out.print("Ket qua: ");
int maxTruoc = a[0];
System.out.print(a[0] + " ");
for (int i = 1; i < n; i++) {
if (a[i] >= maxTruoc) {
System.out.print(a[i] + " ");
maxTruoc = a[i];
}
}
System.out.println();
sc.close();
}
}Chạy với 3 1 4 1 5 9 2 6:
Ket qua: 3 4 5 9
Trace:
i |
a[i] |
maxTruoc trước |
a[i] >= max? |
In | maxTruoc sau |
|---|---|---|---|---|---|
| 0 | 3 | — | (luôn in phần tử đầu) | 3 | 3 |
| 1 | 1 | 3 | không | — | 3 |
| 2 | 4 | 3 | có | 4 | 4 |
| 3 | 1 | 4 | không | — | 4 |
| 4 | 5 | 4 | có | 5 | 5 |
| 5 | 9 | 5 | có | 9 | 9 |
| 6 | 2 | 9 | không | — | 9 |
| 7 | 6 | 9 | không | — | 9 |
Kiểm thử: dãy tăng dần 1 2 3 → in cả 3;
dãy giảm 5 4 3 → chỉ in 5; dãy bằng nhau
2 2 2 → in cả 3 (vì "không nhỏ hơn"). Lỗi:
dùng > thay >= → bỏ mất phần tử bằng
nhau; không in phần tử đầu → thiếu. Câu hỏi: vì sao
phải cập nhật maxTruoc sau khi in?
Bài 10 — Ma trận chỉ gồm 0 và 1
Đề: Ma trận vuông A cấp n
gồm các số nguyên dương. A được gọi là "ma trận đơn vị" nếu
tất cả phần tử đều là 0 hoặc 1. Viết chương trình kiểm
tra một ma trận có phải "ma trận đơn vị" hay không.
Lưu ý thuật ngữ: "ma trận đơn vị" trong toán học là ma trận có 1 trên đường chéo chính và 0 ở chỗ khác. Đề này định nghĩa khác (chỉ cần mọi phần tử ∈ {0,1}). Hãy làm đúng theo đề, và nếu muốn thì làm thêm phần "kiểm tra đơn vị đúng nghĩa" ở mục mở rộng.
// ===== MaTranDonVi.java =====
import java.util.Scanner;
public class MaTranDonVi {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhap n: ");
int n = sc.nextInt();
if (n <= 0) {
System.out.println("n phai > 0");
sc.close();
return;
}
int[][] a = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print("a[" + i + "][" + j + "] = ");
a[i][j] = sc.nextInt();
}
}
boolean ok = true;
for (int i = 0; i < n && ok; i++) {
for (int j = 0; j < n; j++) {
if (a[i][j] != 0 && a[i][j] != 1) {
ok = false;
break; // thoat vong trong
}
}
}
System.out.println(ok ? "La ma tran 0/1" : "Khong phai ma tran 0/1");
sc.close();
}
}Chạy với
1 0 1
0 1 0
0 0 1
→ La ma tran 0/1.
Trace (ma trận có số 2):
i |
j |
a[i][j] |
Hợp lệ? | ok |
|---|---|---|---|---|
| 0 | 0 | 1 | có | true |
| 0 | 1 | 2 | không | false → break |
Kiểm thử: toàn 0 → đúng; có
-1/2 → sai; n = 1 với
a[0][0] = 5 → sai. Lỗi: break
chỉ thoát vòng trong → dùng điều kiện
i < n && ok để thoát cả ngoài; hoặc
return ngay. Câu hỏi: vì sao đặt
&& ok trong điều kiện vòng ngoài thay vì kiểm tra
sau?
Mở rộng — kiểm tra đơn vị đúng nghĩa:
boolean donVi = (a.length == n);
for (int i = 0; i < n && donVi; i++)
for (int j = 0; j < n; j++)
if (a[i][j] != (i == j ? 1 : 0)) { donVi = false; break; }Bảng tổng hợp 10 bài
| # | Bài | Điểm dễ sai nhất |
|---|---|---|
| 1 | Nhập tên | nextInt rồi nextLine |
| 2 | Thứ trong tuần | thiếu break |
| 3 | Bình phương | quên static, quên return |
| 4 | Bội số của 5 | bắt đầu i = 0 |
| 5 | 10 nguyên tố | đếm bằng dem, không bằng khoảng |
| 6 | Chẵn lẻ | % 2 == 1 với số âm |
| 7 | Nguyên âm | chữ hoa, chuỗi rỗng |
| 8 | Cặp bằng nhau | i < n - 1 |
| 9 | Không nhỏ hơn trước | >= vs >; in phần tử đầu |
| 10 | Ma trận 0/1 | thoát cả hai vòng lặp |