You are on page 1of 21

https://blog.28tech.com.

vn/c-mang-danh-dau
#include <stdio.h>

int binary_search(int a[], int n, int x){


//Khởi tạo left, right
int l = 0, r = n - 1;
while(l <= r){
//Tính chỉ số của phần tử ở giữa
int m = (l + r) / 2;
if(a[m] == x){
return 1; // tìm thấy
}
else if(a[m] < x){
//tìm kiếm ở bên phải
l = m + 1;
}
else{
//tìm kiếm ở bên trái
r = m - 1;
}
}
return 0; // l > r
}

int main(){
int n = 12, x = 24, y = 6;
int a[12] = {1, 2, 3, 4, 5, 5, 7, 9, 13, 24, 27, 28};
if(binary_search(a, n, x)){
printf("FOUND\n");
}
else printf("NOT FOUND\n");
if(binary_search(a, n, y)){
printf("FOUND\n");
}
else printf("NOT FOUND\n");
return 0;
}
Output :
FOUND
NOT FOUND

Ví dụ 1. Tìm phần tử X = 3 trong mảng A[] = {1, 1, 3, 4, 5, 8, 9, 12, 21, 32}


Ban đầu : l = 0, r = 9
1. Vòng lặp 1, l = 0, r = 9 , m = (l + r) / 2 = 4, A[m] = 5 > X => Cập nhật r = m - 1 = 3
2. Vòng lặp 2, l = 0, r = 3, m = (l + r) / 2 = 1, A[m] = 1 < X => Cập nhật l = m + 1 = 2
3. Vòng lặp 3, l = 2, r = 3, m = (l + r) / 2 = 2, A[m] = 3 = X => Tìm thấy X và kết thúc chương
trình
Ví dụ 2. Tìm phần tử X = 2 trong mảng A[] = {1, 1, 3, 4, 5, 8, 9, 12, 21, 32}
Ban đầu : l = 0, r = 9
1. Vòng lặp 1, l = 0, r = 9, m = (l + r) / 2 = 4, A[m] = 4 > X => Cập nhật r = m - 1 = 3
2. Vòng lặp 2, l = 0, r = 3, m = (l + r) / 2 = 1, A[m] = 1 < X => Cập nhật l = m + 1 = 2
3. Vòng lặp 3, l = 2, r = 3, m = (l + r) / 2 = 2, A[m] = 3 > X => Cập nhật r = m - 1 - 1
4. Vòng lặp 4, l = 2, r = 1, l > r nên vòng lặp kết thúc và không tìm thấy X

2. Tìm Kiếm Nhị Phân Biến Đổi


Bài toán 1. Tìm vị trí đầu tiên của phần tử X trong mảng đã sắp tăng dần
Tương tự như thuật toán tìm kiếm nhị phân nhưng khi tìm thấy phần tử X trong mảng thì ta chỉ
lưu lại kết quả và cố gắng tìm kiếm thêm ở nửa bên trái.
#include <stdio.h>

int firstPos(int a[], int n, int x){


int l = 0, r = n - 1;
int pos = -1; // cập nhật kết quả
while(l <= r){
//Tính chỉ số của phần tử ở giữa
int m = (l + r) / 2;
if(a[m] == x){
pos = m; // lưu lại
//Tìm thêm bên trái
r = m - 1;
}
else if(a[m] < x){
//tìm kiếm ở bên phải
l = m + 1;
}
else{
//tìm kiếm ở bên trái
r = m - 1;
}
}
return pos;
}

int main(){
int n = 10, x = 3;
int a[10] = {1, 1, 2, 2, 3, 3, 3, 5, 7, 9};
int res = firstPos(a, n, x);
if(res == -1){
printf("%d khong xuat hien trong mang\n");
}
else{
printf("Vi tri dau tien cua %d trong mang : %d\n", x, res);
}
return 0;
}
Output :
Vi tri dau tien cua 3 trong mang : 4

Bài toán 2 : Tìm vị trí cuối cùng của phần tử X trong mảng đã sắp tăng dần
Tương tự như thuật toán tìm kiếm nhị phân nhưng khi tìm thấy phần tử X trong mảng thì ta chỉ
lưu lại kết quả và cố gắng tìm kiếm thêm ở nửa bên phải.
#include <stdio.h>

int lastPos(int a[], int n, int x){


int l = 0, r = n - 1;
int pos = -1; // cập nhật kết quả
while(l <= r){
//Tính chỉ số của phần tử ở giữa
int m = (l + r) / 2;
if(a[m] == x){
pos = m; // lưu lại
//Tìm thêm bên phải
l = m + 1;
}
else if(a[m] < x){
//tìm kiếm ở bên phải
l = m + 1;
}
else{
//tìm kiếm ở bên trái
r = m - 1;
}
}
return pos;
}

int main(){
int n = 10, x = 3;
int a[10] = {1, 1, 2, 2, 3, 3, 3, 5, 7, 9};
int res = lastPos(a, n, x);
if(res == -1){
printf("%d khong xuat hien trong mang\n");
}
else{
printf("Vi tri cuoi cung cua %d trong mang : %d\n", x, res);
}
return 0;
}
Output :
Vi tri cuoi cung cua 3 trong mang : 6

Bài toán 3 : Tìm vị trí đầu tiên của phần tử lớn hơn hoặc bằng X trong mảng đã sắp tăng dần
Tương tự như thuật toán tìm kiếm nhị phân nhưng khi tìm thấy phần tử ở giữa lớn hơn hoặc bằng
phần tử X thì ta chỉ lưu lại kết quả và cố gắng tìm kiếm thêm ở nửa bên trái.
#include <stdio.h>

int firstPos(int a[], int n, int x){


int l = 0, r = n - 1;
int pos = -1; // cập nhật kết quả
while(l <= r){
//Tính chỉ số của phần tử ở giữa
int m = (l + r) / 2;
if(a[m] >= x){
pos = m; // lưu lại
//Tìm thêm bên trái
r = m - 1;
}
else{
//tìm kiếm ở bên phải
l = m + 1;
}
}
return pos;
}

int main(){
int n = 10, x = 4;
int a[10] = {1, 1, 2, 2, 3, 3, 3, 5, 7, 9};
int res = firstPos(a, n, x);
if(res == -1){
printf("%d khong xuat hien trong mang\n");
}
else{
printf("Vi tri dau tien cua phan tu >= %d trong mang : %d\n", x, res);
}
return 0;
}
Output :
Vi tri dau tien cua phan tu >= 4 trong mang : 7

Câu 3. Khiêu vũ
Câu 3. Khiêu vũ (5,0 điểm)
Ở thành phố Anpha xinh đẹp mọi người sống rất bình yên và hạnh phúc. Cuối tuần họ
thường tổ chức các buổi tiệc khiêu vũ cho cư dân trong thành phố. Sắp tới họ sẽ tổ chức một
buổi tiệc khiêu vũ mang tên “Vũ điệu mùa xuân”. Điều đặc biệt trong buổi tiệc này là chỉ
những cặp đôi có chiều cao chênh lệch nhau đúng bằng số k cho trước thì mới được khiêu vũ
cùng nhau (không phân biệt giới tính). Có 1 người tham gia buổi tiệc khiêu vũ, chiều cao của
n người này lần lượt là h1, h2, ..., hn.
Yêu cầu: Hãy đếm xem có tất cả bao nhiêu cặp đôi có thể khiêu vũ cùng nhau.
Dữ liệu: Vào từ tệp văn bản KHIEUVU.INP gồm 2 dòng:
• Dòng đầu ghi 2 số nguyên n, k với n là số lượng người tham gia buổi tiệc, k là độ
chênh lệch chiều cao yêu cầu (2 ≤ n ≤ 105

; 0 ≤ k ≤ 109
).

• Dòng thứ 2 ghi n số h1, h2, ..., hn là chiều cao của n người tham gia buổi tiệc (hi ≤ 109
).

Các số trên một dòng cách nhau bởi dấu cách.


Kết quả: Ghi vào tệp văn bản KHIEUVU.OUT một số duy nhất là kết quả của bài toán.
Ví dụ:
KHIEUVU.INP KHIEUVU.OUT Giải thích
72
10 7 5 12 1 9 8

4 Có 4 cặp đôi có độ chênh lệch


chiều cao bằng 2 là: (1,4),
(1,7), (2,3), (2,6)

Ràng buộc:
• 50% số test ứng với 50% số điểm thỏa mãn n ≤ 103, hi ≤ 106
• 50% số test còn lại ứng với 50% số điểm thỏa mãn n ≤ 105, hi ≤109

sort(h)
count = 0
for i in range(n):
j = bisect_left(h, h[i]+k, i+1, n)
if j < n and h[j] == h[i] + k:
count += 1
return count
sort(a+1,a+n+1);
int c = 0;
for(int i =1; i<= n;i++)
{ j = tknp(h,n,h[i] + k);
If( j<=n) and (a[j] == a[i] + k)
c++;
}

Bài tập.
Cho số nguyên dương n, tiếp theo là n số nguyên dương của một dãy a, cuối cùng là một
số s.
Hãy đưa ra dãy con liên tiếp đầu tiên của dãy a sao cho tổng của dãy đó bằng s. In dãy đó ra
màn hình, sau mỗi phần tử có một khoảng trắng. Nếu không tồn tại dãy đó thì in ra "-1".
Ví dụ:
 Test mẫu 1:

Input Output
5
12345 23
5

Với a = [1, 2, 3, 4, 5] và s = 5 thì kết quả mong muốn là: "2 3 ".

 Test mẫu 2:

Input Output
3
123 -1
4

Với a = [1, 2, 3] và s = 4 thì kết quả mong muốn là: "-1"
Hướng dẫn bài tập.
Tạo dãy b, với b[0] = a[0], b[i] = b[i-1] + a[i].
Ví dụ với a = [1, 2, 3, 4, 5] và s = 5. Dãy b được tạo ra là [1, 3, 6, 10, 15].
Mục đích chúng ta cần làm là cần tìm vị trí l và i sao cho b[i] - b[l] = s.
Như vậy dãy cần tìm sẽ là các phần tử từ ví trí l+1 đến i ở trong dãy a.
Dùng biến i duyệt dãy b, nếu b[i] ≥ s (dãy đó có thể kết thúc tại i) tìm vị trí của b[i]-s trong
dãy b, nếu tồn tại vị trí l đó thì đưa ra dãy từ l+1 đến i.
Code mẫu:
Ngôn ngữ C++:
#include<iostream>

using namespace std;

int a[100001];
int b[100001];
int BinSearch(int a[], int n, int x){
int l = 0, r = n-1;
while (l < r){
int mid = (l+r)/2;
if (a[mid] < x){
l = mid+1;
}
else{
r = mid;
}
}
if (a[l] == x){
return l;
}
return -1;
}

void printArray(int a[], int n, int l, int r){


for (int i = l; i <= r; i++){
cout << a[i] << " ";
}
}

bool solve(int a[], int b[], int n, int s){


b[0] = a[0];
for (int i = 1; i < n; i++){
b[i] = b[i-1] + a[i];
}
for (int i = 0; i < n; i++){
if (b[i] == s){
printArray(a, n, 0, i);
return true;
}
if (b[i] > s){
int l = BinSearch(b, n, b[i]-s);
if (l != -1){
printArray(a, n, l+1, i);
return true;
}
}
}
}

int main(){
int n, s;
cin >> n;
for (int i = 0; i < n; i++){
cin >> a[i];
}
cin >> s;
bool k = solve(a, b, n, s);
if (!k){
cout << -1;
}
return 0;
}

[C]. Bài Tập Về Dãy Số


Bài tập về dãy số là dạng bài tập gây nhiều khó khăn cho các bạn mới học, trong bài viết này
mình sẽ hướng dẫn các bạn những bài tập về dãy số thường gặp.

NỘI DUNG :
 Dãy Con Cỡ K Có Tổng Lớn Nhất
 Dãy Con Giống Nhau Dài Nhất
 Dãy Con Khác Nhau Dài Nhất
 Kiểm Tra Mảng Tăng Dần
 Dãy Nguyên Tố Dài Nhất
 Video Tutorial

1. Dãy Con Cỡ K có Tổng Lớn Nhất


Cho mảng A[] gồm N phần tử và số nguyên K, bạn hãy tính tổng các dãy con liên tiếp có K phần
tử của mảng A[] và in ra màn hình

Ví dụ A[] = {3, 2, 1, 5, 6, 7, 2} và K = 3 các bạn sẽ có các dãy con : {3, 2,1}, {2, 1, 5}, {1, 5, 6}, {5,
6, 7}, {6, 7, 2}

Thuật toán :

1. Duyệt các chỉ số i từ 0 tới N - K đại diện cho phần tử đầu tiên của dãy con
2. Tính tổng K phần tử liên tiếp từ chỉ số i và in ra màn hình

Code :

#include <stdio.h>

int main(){
int n = 7, k = 3;
int a[7] = {3, 2, 1, 5, 6, 7, 2};
int tong = 0;
for(int i = 0; i <= n - k; i++){
//reset giá trị của tổng ở mỗi dãy con
tong = 0;
for(int j = 0; j < k; j++){
tong += a[i + j];
}
printf("%d ", tong);
}
return 0;
}
Output :

6 8 12 18 15

2. Dãy Con Giống Nhau Dài Nhất


Cho mảng A[] gồm N phần tử bạn hãy tìm độ dài của dãy con chứa các phần tử giống nhau dài
nhất.

Ví dụ A[] = {1, 2, 2, 2, 3, 3, 5, 4, 4, 4, 4, 2} thì dãy con {4, 4, 4, 4} là dãy con dài nhất chứa các
phần tử giống nhau

Thuật toán :

1. Khởi tạo 1 biến đếm bằng 1 đại diện cho A[0]


2. Duyệt từ chỉ số 1 tới N - 1 và so sánh A[i] với A[i - 1]
3. Nếu A[i] = A[i - 1] thì tăng biến đếm
4. Nếu A[i] != A[i - 1] thì cập nhật kết quả thông qua biến đếm sau đó reset biến đếm về 1 để
đếm lại dãy con bắt đầu từ A[i]

Code :

#include <stdio.h>

int main(){
int n = 12;
int a[12] = {1, 2, 2, 2, 3, 3, 5, 4, 4, 4, 4, 2};
int dem = 1, res = 1;
for(int i = 1; i < n; i++){
if(a[i] == a[i - 1]){
++dem;
}
else{
if(res < dem){
res = dem;
}
dem = 1;
}
}
//Chú ý cập nhật dãy con dài nhất kết thúc tại A[n - 1]
if(dem > res){
res = dem;
}
printf("%d\n", res);
return 0;
}
Output :

4
Bạn thử làm thêm yêu cầu liệt kê tất cả các dãy con giống nhau dài nhất, ví dụ A[] = {1, 2, 2, 2, 3,
3, 5, 4, 4, 4, 3, 2} thì có 2 dãy con thỏa mãn là {2, 2, 2} và {4, 4, 4}

3.Dãy Con Khác Nhau Dài Nhất


Cho mảng A[] gồm N phần tử bạn hãy tìm độ dài lớn nhất của dãy con chứa các phần tử sao cho
không có hai phần tử liền kề nào giống nhau.

Ví dụ A[] = {1, 2, 3, 2, 3, 3, 5, 4, 4, 4, 4, 2} thì dãy con {1, 2, 3, 2, 3} là dãy con cần tìm

Thuật toán :

1. Khởi tạo 1 biến đếm bằng 1 đại diện cho A[0]


2. Duyệt từ chỉ số 1 tới N - 1 và so sánh A[i] với A[i - 1]
3. Nếu A[i] != A[i - 1] thì tăng biến đếm
4. Nếu A[i] = A[i - 1] thì cập nhật kết quả thông qua biến đếm sau đó reset biến đếm về 1 để
đếm lại dãy con bắt đầu từ A[i]
Code :

#include <stdio.h>

int main(){
int n = 12;
int a[12] = {1, 2, 3, 2, 3, 3, 5, 4, 4, 4, 4, 2};
int dem = 1, res = 1;
for(int i = 1; i < n; i++){
if(a[i] != a[i - 1]){
++dem;
}
else{
if(res < dem){
res = dem;
}
dem = 1;
}
}
//Chú ý cập nhật dãy con dài nhất kết thúc tại A[n - 1]
if(dem > res){
res = dem;
}
printf("%d\n", res);
return 0;
}
Output :

4. Kiểm Tra Mảng Tăng Dần


Bài toán yêu cầu bạn kiểm tra mảng A[] có N phần tử đã cho có tăng dần (giảm dần hay không),
mảng tăng dần thỏa mãn yêu cầu phần tử đứng sau lớn hơn hoặc bằng phần tử đứng ngay trước
nó.

Ví dụ A[] = {1, 2, 2, 3, 4, 5} là mảng tăng dần

Thuật toán :

Xét N - 1 cặp phần tử đứng cạnh nhau, nếu N - 1 cặp phần tử này đều thỏa mãn phần tử đứng
sau A[i] lớn hơn hoặc bằng phần tử ngay trước nó là A[i - 1] thì mảng tăng dần

Chú ý không cần kiểm tra A[0] và phần tử đứng trước nó.

Code :

#include <stdio.h>

int check(int a[], int n){


for(int i = 1; i < n; i++){
if(a[i] < a[i - 1]){
return 0;
}
}
return 1;
}

int main(){
int n = 6;
int a[6] = {1, 2, 2, 3, 4, 5};
if(check(a, n)){
printf("Mang tang dan\n");
}
else{
printf("Mang khong tang dan\n");
}
return 0;
}
Output :
Mang tang dan

5. Dãy Nguyên Tố Dài Nhất


Cho mảng A[] gồm N phần tử, hãy in ra dãy con dài nhất chứa toàn số nguyên tố, nếu có nhiều
dãy con thỏa mãn thì chọn ra dãy con có tổng lớn nhất và xuất hiện đầu tiên.

Ví dụ A[] = {2, 3, 5, 8, 7, 11, 19, 4, 10, 23, 5} thì dãy con {7, 11, 19} có độ dài 3 và có tổng lớn
nhất.

Thuật toán :

1. Khởi tạo 1 biến đếm bằng 0 và một biến tổng bằng 0


2. Duyệt qua các phần tử A[i] trong mảng từ chỉ số 0 tới N - 1
3. Nếu phần tử A[i] là số nguyên tố thì tăng biến đếm và cộng thêm A[i] vào biến tổng
4. Nếu phần tử A[i] không phải là số nguyên tố thì cập nhật kết quả, sau đó reset biến đếm
về 0 và tổng về 0

Code :

#include <stdio.h>
#include <math.h>

int prime(int n){


if(n < 2){
return 0;
}
for(int i = 2; i <= sqrt(n); i++){
if(n % i == 0){
return 0;
}
}
return 1;
}

int main(){
int n = 11;
int a[11] = {2, 3, 5, 8, 7, 11, 19, 4, 10, 23, 5};
int dem = 0, tong = 0;
int res_dem = 0, res_tong = 0, start = -1;
for(int i = 0; i < n; i++){
if(prime(a[i])){
++dem;
tong += a[i];
}
else{
if(dem > res_dem){
res_dem = dem;
res_tong = tong;
start = i - res_dem;
}
else if(dem == res_dem){
if(tong > res_tong){
res_tong = tong;
start = i - res_dem;
}
}
dem = 0; tong = 0;
}
}
//cap nhat day con ket thuc tai a[n - 1]
if(dem > res_dem){
res_dem = dem;
res_tong = tong;
start = n - res_dem;
}
else if(dem == res_dem){
if(tong > res_tong){
res_tong = tong;
start = n - res_dem;
}
}
if(start == -1){
printf("Mang khong chua so nguyen to !\n");
}
else{
for(int i = 0; i < res_dem; i++){
printf("%d ", a[i + start]);
}
}
return 0;
}
Output :

7 11 19
1. Lý Thuyết Mảng Đánh Dấu

Bài Toán : Cho mảng A[] gồm N phần tử là các số nguyên trong đoạn [0, 106]. Hãy đếm các giá trị khác
nhau trong mảng ?

Mình đã hướng dẫn các bạn cách sử dụng 2 vòng for lồng nhau để giải quyết bài toán trên, nếu bạn
chưa biết cách làm đó có thể tham khảo tại đây

Để giải quyết bài toán trên bạn có thể dùng 1 mảng đánh dấu đủ lớn để đánh dấu sự xuất các giá trị
trong mảng, vì các phần tử trong mảng đều nằm trong đoạn từ [0, 106] nên chỉ cần dùng một mảng số
nguyên mà chỉ số của nó có thể đánh dấu được hết các giá trị [0, 106] là giải quyết được bài toán.

Ý tưởng ở đây đó là bạn sẽ sử dụng chỉ số của mảng đánh dấu để đánh dấu giá trị tương ứng với chỉ số
đó đã xuất hiện trong mảng. Ban đầu tất cả các phần tử trong mảng đánh dấu có giá trị là 0, khi bạn gặp
một giá trị trong mảng thì sẽ chuyển phần tử trong mảng đánh dấu tại chỉ số đó thành 1.

Ví dụ mảng đánh dấu là mark[] và khi gặp phần tử trong mảng A[] là 3 thì mark[3] = 1

Sau khi đánh dấu xong các giá trị xuất hiện thì bạn chỉ cần duyệt mảng đánh dấu và xem phần tử nào
trong mảng đánh dấu có giá trị là 1 để đếm hoặc liệt kê.

Code :

#include <stdio.h>
//Chỉ số của mark là từ 0 tới 10^6, ban đầu toàn bộ mảng mark[] = 0

int mark[1000001];

int main(){
int n = 8;
int a[8] = {3, 1, 3, 0, 2, 4, 1, 6};
//đánh dấu
for(int i = 0; i < n; i++){
//Lấy a[i] làm chỉ số và chuyển mark[a[i]] = 11
mark[a[i]] = 1;
}
int dem = 0;
//Bạn có thể duyệt từ i = 0 tới giá trị max trong mảng cũng được
for(int i = 0; i <= 1000000; i++){
if(mark[i] == 1){
++dem;
}
}
printf("So luong phan tu khac nhau : %d\n", dem);
return 0;
}
Output :

So luong phan tu khac nhau : 6


Giải thích :

Mảng mark ban đầu :

i 0 1 2 3 4 5 6 7 ...
mark[i] 0 0 0 0 0 0 0 0 0.
i = 0, a[i] = 3, mark[3] = 1

i 0 1 2 3 4 5 6 7 ...
mark[i] 0 0 0 1 0 0 0 0 0.
i = 1, a[i] = 1, mark[1] = 1

i 0 1 2 3 4 5 6 7 ...
mark[i] 0 1 0 1 0 0 0 0 0.
i = 2, a[i] = 3, mark[3] = 1

i 0 1 2 3 4 5 6 7 ...
mark[i] 0 1 0 1 0 0 0 0 0.
....

i = 7, a[i] = 6, mark[6] = 1

i 0 1 2 3 4 5 6 7 ...
mark[i] 1 1 1 1 1 0 1 0 0.

Chú ý khi sử dụng mảng đánh dấu :

 Mảng đánh dấu không thể sử dụng được với số âm, vì chỉ số trong mảng không thể là số âm
 Mảng đánh dấu không sử dụng được khi giá trị cần đánh dấu vượt chỉ số của mảng mà bạn có
thể khai báo
 Thông thường bạn chỉ áp dụng được kỹ thuật này khi các phần tử trong mảng có giá trị trong
đoạn [0, 107]
 Chú ý sử dụng mảng đánh dấu đủ lớn để không lỗi bộ nhớ, ví dụ bạn cần đánh dấu các phần tử
trong đoạn [0, 103] thì mảng cỡ 1001 là đủ rồi, hoặc có thể lớn hơn

2.Bài Toán Liệt Kê Giá Trị Khác Nhau

Bài Toán 1 : Cho mảng A[] gồm N phần tử là số nguyên trong đoạn [0, 106], hãy liệt kê các giá trị khác
nhau trong mảng theo thứ tự từ nhỏ tới lớn

Ý tưởng là sử dụng mảng đánh dấu sau đó liệt kê các số từ nhỏ tới lớn xuất hiện trong mảng và in ra
nếu giá trị đó được đánh dấu.

Code :

#include <stdio.h>
//Chỉ số của mark là từ 0 tới 10^6, ban đầu toàn bộ mảng mark[] = 0

int mark[1000001];

int main(){
int n = 10;
int a[10] = {3, 1, 3, 0, 2, 4, 1, 14, 12, 7};
//đánh dấu
int max_val = -1000000000;
for(int i = 0; i < n; i++){
//Lấy a[i] làm chỉ số và chuyển mark[a[i]] = 11
mark[a[i]] = 1;
if(a[i] > max_val){
max_val = a[i];
}
}
printf("Gia tri khac nhau trong mang : ");
for(int i = 0; i <= max_val; i++){
if(mark[i] == 1){
printf("%d ", i);
}
}
return 0;
}
Output :

Gia tri khac nhau trong mang : 0 1 2 3 4 7 12 14

Bài Toán 2 : Cho mảng A[] gồm N phần tử là số nguyên trong đoạn [0, 106], hãy liệt kê các giá trị khác
nhau trong mảng theo thứ tự xuất hiện trong mảng, mỗi giá trị chỉ liệt kê 1 lần

Ý tưởng là sử dụng mảng đánh dấu sau đó liệt kê các theo thứ tự xuất hiện trong mảng và in ra nếu giá
trị đó được đánh dấu.
Sau khi in ra giá trị thì bạn bỏ đánh dấu giá trị đó để tránh in trùng.

Code :

#include <stdio.h>

//Chỉ số của mark là từ 0 tới 10^6, ban đầu toàn bộ mảng mark[] = 0

int mark[1000001];

int main(){
int n = 10;
int a[10] = {3, 1, 3, 0, 2, 4, 1, 14, 12, 7};
//đánh dấu
for(int i = 0; i < n; i++){
//Lấy a[i] làm chỉ số và chuyển mark[a[i]] = 11
mark[a[i]] = 1;
}
printf("Gia tri khac nhau trong mang : ");
for(int i = 0; i < n; i++){
if(mark[a[i]] == 1){
printf("%d ", a[i]);
//Bỏ đánh dấu
mark[a[i]] = 0;
}
}
return 0;
}
Output :

Gia tri khac nhau trong mang : 3 1 0 2 4 14 12 7


3. Bài Toán Tần Suất

Mảng đánh dấu rất hữu dụng đối với những bài toán liên quan tới tần suất xuất hiện của phần tử trong
mảng.

Trong bài toán liên quan tới tần suất thì mảng đánh dấu mark[] có vai trò đếm tần suất thay vì chỉ đánh
dấu. Khi đánh dấu giá trị a[i] trong mảng thì bạn cần cho mark[a[i]] = 1 còn khi bạn muốn đếm xem
a[i] đã xuất hiện bao nhiêu lần thì bạn thay đổi câu lệnh cập nhật thành mark[a[i]]++

Bài toán : Cho mảng A[] gồm N phần tử là số nguyên trong đoạn [0, 106], hãy đếm xem mỗi phần tử
trong mảng xuất hiện bao nhiêu lần và in ra theo thứ tự từ nhỏ tới lớn.

Code :

#include <stdio.h>

//Chỉ số của mark là từ 0 tới 10^6, ban đầu toàn bộ mảng mark[] = 0

int mark[1000001];

int main(){
int n = 10;
int a[10] = {3, 1, 3, 0, 2, 4, 1, 14, 3, 2};
//đếm tần suất
int max_val = -1000000000;
for(int i = 0; i < n; i++){
//Lấy a[i] làm chỉ số và chuyển mark[a[i]] tăng thêm 1 đơn vị
mark[a[i]]++;
if(a[i] > max_val){
max_val = a[i];
}
}
for(int i = 0; i <= max_val; i++){
if(mark[i]){
printf("%d xuat hien %d lan\n", i, mark[i]);
}
}
return 0;
}
Output :

0 xuat hien 1 lan


1 xuat hien 2 lan
2 xuat hien 2 lan
3 xuat hien 3 lan
4 xuat hien 1 lan
14 xuat hien 1 lan
Các bài toán sau bạn tự triển khai coi như bài tập :

Bài 1. Liệt kê các phần tử xuất hiện ít nhất 2 lần trong mảng theo thứ tự xuất hiện trong mảng, mỗi
phần tử chỉ liệt kê 1 lần

Ví dụ A[] = {3, 1, 1, 1, 2, 3, 4, 0, 3, 2} thì output sẽ là 3, 1, 2

Bài 2. Liệt kê các phần tử xuất hiện đúng 1 lần trong mảng theo thứ tự xuất hiện trong mảng

Ví dụ A[] = {3, 1, 1, 1, 2, 3, 4, 0, 3, 2} thì output sẽ là 4, 0, 2

Bài 3. Liệt kê các phần tử xuất hiện nhiều nhất trong mảng, nếu có nhiều phần tử có cùng số lần xuất
hiện nhiều nhất thì liệt kê theo thứ tự xuất hiện trong mảng

Ví dụ A[] = {3, 1, 1, 1, 2, 3, 4, 0, 3, 2} thì output sẽ là 3, 1

Bài 4. Cho mảng A[] và B[], hãy liệt kê các giá trị thuộc 1 trong 2 mảng, mỗi giá trị liệt kê 1 lần theo
thứ tự tăng dần

Ví dụ A[] = {3, 1, 2, 4, 4, 1, 5} và B[] = {0, 1, 2, 3, 5, 7} thì output là 0, 1, 2, 3, 4, 5, 7

You might also like