Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Các bạn nên đọc và nắm vững phần lý thuyết dưới đây trước khi bắt đầu làm bài tập nhé!
Author: Loser1 from Learning AI With Losers
Chào các bạn losers thân mến! Loser1 từ Learning AI With Losers quay trở lại đây! 👋
Sau khi đã cùng nhau khám phá lý thuyết về Linear Search và Binary Search trong phần trước, đã đến lúc chúng ta thử sức với những bài tập thực tế. Và hôm nay, mình đã chọn lọc những bài tập “chất lượng” từ đề thi của trường HCMUS để các bạn luyện tập! 🎯
Các bài tập trong phần này được chọn lọc từ đề thi của trường Đại học Khoa học Tự nhiên (HCMUS), được biết đến với:
Mình sẽ chia bài tập thành các phần:
Với mỗi bài tập, mình sẽ:
Nếu bạn chưa đọc phần lý thuyết về Linear Search và Binary Search, hãy đọc lại tại đây để có nền tảng vững chắc trước khi làm bài tập nhé!
Let’s solve some problems! 🚀
Note: Các bài tập được sắp xếp theo độ khó tăng dần. Hãy giải tuần tự để xây dựng tư duy một cách vững chắc nhé!
Đề bài:
Viết hàm kiểm tra xem có tồn tại hai phần tử (a) trong mảng (A) và (b) trong mảng (B) sao cho (a + b = k).
Yêu cầu sử dụng Merge Sort và Binary Search.
Đáp án:
void Merge(int A1[], int A2[]) {
// Triển khai logic merge
}
void MergeSort(int Arr[], int n, int left, int right) {
// Triển khai logic MergeSort
}
int Sum(int A[], int B[], int n, int k) {
MergeSort(A, n, 0, n-1);
MergeSort(B, n, 0, n-1);
int left = 0;
int right = n-1;
while (left <= n-1 && right >= 0) {
if (A[left] + B[right] == k) {
return 1;
} else if (A[left] + B[right] > k) {
right--;
} else {
left++;
}
}
return 0;
}
Đề bài:
Viết hàm tìm vị trí của phần tử (k) trong mảng đã bị xoay (ví dụ: ([4,5,6,7,0,1,2])).
Đáp án:
int searchArray(int a[], int n, int k) {<br> int left = 0, right = n - 1;<br> while (left <= right) {<br> int mid = left + (right - left) / 2;<br> if (a[mid] == k) return mid;<br> <br> if (a[left] <= a[mid]) { // Nửa trái đã được sắp xếp<br> if (a[left] <= k && k < a[mid]) <br> right = mid - 1; // Tìm bên trái<br> else <br> left = mid + 1; // Tìm bên phải<br> } <br> else { // Nửa phải đã được sắp xếp<br> if (a[mid] < k && k <= a[right]) <br> left = mid + 1; // Tìm bên phải<br> else <br> right = mid - 1; // Tìm bên trái<br> }<br> }<br> return -1;<br>}<br><br>
Đề bài:
Đáp án:
// Hàm tính số lần xuất hiện tối thiểu của k
int min_appearances(int k) {
return k * (int)sqrt(k) + (k / 2);
}
// Tìm chỉ số đầu tiên lớn hơn k (Upper Bound)
int UpperBound(int a[], int L, int R, int k) {
int ans = R + 1;
while (L <= R) {
int mid = L + (R - L) / 2;
if (a[mid] > k) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return ans;
}
// Hàm chính tính số giá trị khác nhau thỏa mãn
int Cau2(int a[], int L, int R) {
if (L > R) return 0;
int count = 0;
while (L <= R) {
int key = a[L]; // Lấy giá trị hiện tại
int min_occur = min_appearances(key); // Tính số lần xuất hiện tối thiểu của key
// Tìm vị trí cuối cùng của key
int upper_pos = UpperBound(a, L, R, key);
int actual_occur = upper_pos - L;
// Kiểm tra nếu số lần xuất hiện thực tế của key lớn hơn hoặc bằng min_occur
if (actual_occur >= min_occur) {
count++; // Tăng số lượng giá trị thỏa mãn
}
// Nhảy tới giá trị khác
L = upper_pos;
}
return count;
}
Độ phức tạp:
Với mỗi giá trị duy nhất, ta thực hiện binary search một lần: O(log n)
Số giá trị duy nhất tối đa là O(sqrt(n)) do điều kiện về số lần xuất hiện
Do đó độ phức tạp tổng thể là O(sqrt(n) * log n) < O(n)
Đề bài:
Đáp án :
Khởi đầu :
Cho A[] , tìm 6
L = 0 , R = 9
Vòng While :
Lần 1 : L = 0 , R = 9 , M = (L+R)/2 = (0+9)/2 = 4
A[M] = A[4] = 4
Do A[M] < 6
L = M + 1 = 5
Lần 2 : L = 5 , R = 9 , M = (5+9)/2 = 7
A[M] = A[7] = 7
Do A[M] > 6
R = M-1 = 7-1 = 6
Lần 3 : L = 5 , R = 6 , M = (5+6)/2 = 5
A[M] = A[5] = 5
Do A[M] > 5 :
L = M + 1 = 5+1 = 6
Lần 4 : L = 6 , R = 6 , M = 6
A[M] bằng 6
Đã tìm thấy 6 trong mảng tại vị trí 3
Code:
int BinarySearch(int a[], int L, int R, int k) {
if (L > R) return -1;
int M = L + (R - L) / 2;
if (a[M] == k) return M;
else if (a[M] > k) return BinarySearch(a, L, M-1, k);
else return BinarySearch(a, M+1, R, k);
}
Đề bài:
Cho hai văn bản (A) và (B). So sánh hai phương pháp tìm từ chung:
a) Thơi gian nhanh nhất
b) Bộ nhớ ít nhất
Bài 2 :
a)
Sử dụng bảng băm (Hash Table, có thể sử dụng unordered set):
Đưa tất cả các từ của văn bản B vào một bảng băm.
Duyệt qua từng từ của văn bản A và kiểm tra xem từ đó có tồn tại trong bảng băm của B không.
Độ phức tạc thời gian: O(n + m), với n là số từ của A và m là số từ của B.
Space : O(n+m)
b) Duyệt Trâu (hoặc sort rồi 2 con trỏ) . mỗi từ trong B duyệt qua A 1 lần ….
Space : O(1)
Time : O(n*m)
Để có thể thực hiện thao tác tìm kiếm nhị phân, cây nhị phân phải được sắp xếp theo thứ tự tăng dần hoặc giảm dần.
Độ phức tạp của thao tác tìm kiếm nhị phân là O(log n), nghĩa là độ phức tạp tăng theo logarit của kích thước dữ liệu.
Nếu một quá trình gồm 3 bước xử lý với độ phức tạp lần lượt là O(n^2), O(n^3) và O(n log n), thì độ phức tạp tổng thể của quá trình đó sẽ là O(n^3), vì độ phức tạp của bước xử lý lớn nhất sẽ chi phối độ phức tạp tổng thể.
Trong các câu hỏi liên quan đến tìm kiếm, việc hiểu rõ các khái niệm như tìm kiếm nhị phân, độ phức tạp của các thuật toán tìm kiếm là rất quan trọng. Hy vọng những giải thích trên sẽ giúp bạn hiểu rõ hơn về các vấn đề này.