Courses
Giả sử bạn đang xây dựng một pipeline dữ liệu cho một mô hình học máy. Bạn cần tìm cách tốt nhất để lưu trữ và truy xuất toàn bộ dữ liệu để huấn luyện mô hình đó. Đó chính là lúc cấu trúc dữ liệu phát huy tác dụng!
Bài viết này sẽ cung cấp hướng dẫn toàn diện về các câu hỏi phỏng vấn cấu trúc dữ liệu, bao quát từ những khái niệm cơ bản đến các kỹ thuật nâng cao.
Cấu trúc dữ liệu là gì và vì sao chúng quan trọng?
Cấu trúc dữ liệu là các định dạng chuyên biệt để tổ chức và lưu trữ dữ liệu. Chúng xác định cách các phần tử dữ liệu được sắp xếp và liên kết với nhau, từ đó ảnh hưởng đến mức độ hiệu quả khi bạn truy cập và chỉnh sửa dữ liệu.
Giống như cách bạn sắp xếp đồ đạc ở nhà giúp dễ tìm hơn, cấu trúc dữ liệu quyết định vị trí dữ liệu trong bộ nhớ và tốc độ bạn có thể tìm kiếm, chèn hoặc xóa dữ liệu.
Vậy vì sao bạn nên nắm vững cấu trúc dữ liệu? Cấu trúc dữ liệu là nền tảng của khoa học máy tính. Chúng đóng vai trò quan trọng trong việc xây dựng các hệ thống hiệu quả, có khả năng mở rộng. Ngoài ra, nhiều thuật toán dựa vào những cấu trúc dữ liệu cụ thể để triển khai hiệu quả.
Theo kinh nghiệm của tôi, chúng thiết yếu để thành công trong các lĩnh vực như kỹ thuật phần mềm, khoa học dữ liệu và kỹ thuật dữ liệu. Các buổi phỏng vấn thường đánh giá khả năng giải quyết vấn đề và hiểu biết về các khái niệm cốt lõi của khoa học máy tính; trong đó, kiến thức vững về cấu trúc dữ liệu đặc biệt có giá trị.
Câu Hỏi Phỏng Vấn Cấu Trúc Dữ Liệu Cơ Bản
Để thể hiện hiểu biết về các cấu trúc dữ liệu cơ bản, bạn cần tự tin vào các cấu trúc cốt lõi và cách hiện thực chúng. Những câu hỏi sau sẽ kiểm tra khả năng giải thích ý tưởng và thể hiện kiến thức của bạn.
Có những loại cấu trúc dữ liệu nào?
Cấu trúc dữ liệu được phân loại như sau:
- Cấu trúc dữ liệu tuyến tính: Một cấu trúc dữ liệu được coi là tuyến tính nếu mọi phần tử đều được sắp xếp tuần tự. Trong cấu trúc dữ liệu tuyến tính, các phần tử được lưu trữ theo cách phi phân cấp, nơi mỗi phần tử (trừ phần tử đầu và cuối) đều có phần tử đứng trước và đứng sau.
- Cấu trúc dữ liệu phi tuyến tính: Cấu trúc dữ liệu phi tuyến tính không tạo thành một dãy; thay vào đó, mỗi phần tử được kết nối với hai hoặc nhiều phần tử khác theo cách phi tuyến tính. Các phần tử dữ liệu không được tổ chức theo cấu trúc tuần tự.
Phân biệt mảng và danh sách liên kết.
Mảng và danh sách liên kết đều là cách lưu trữ nhóm phần tử, nhưng chúng hoạt động khác nhau. Dưới đây là những khác biệt chính:
- Mảng. Chúng giống như một hàng hộp trong bộ nhớ, cho phép truy cập phần tử theo chỉ số rất nhanh với độ phức tạp thời gian O(1). Tuy nhiên, việc thêm hoặc xóa phần tử ở giữa khó khăn vì cần dịch chuyển các phần tử khác.
- Danh sách liên kết. Chúng gồm các nút, mỗi nút chứa một phần tử và con trỏ tới nút kế tiếp. Điều này giúp chèn hoặc xóa phần tử mà không ảnh hưởng toàn bộ danh sách dễ hơn, nhưng tìm kiếm phần tử mất nhiều thời gian hơn với độ phức tạp O(n).
Ngăn xếp (stack) là gì?
Ngăn xếp là một danh sách có thứ tự, nơi bạn thêm và loại bỏ phần tử ở một đầu gọi là đỉnh (top). Nó tuân theo nguyên tắc vào sau ra trước (LIFO): phần tử được thêm gần nhất sẽ được lấy ra đầu tiên.
Ngăn xếp được dùng trong nhiều ứng dụng như đánh giá biểu thức, quay lui (backtracking), quản lý bộ nhớ, và lời gọi/trả về hàm.
Bạn triển khai ngăn xếp bằng mảng như thế nào?
Trong Python, list hoạt động như một ngăn xếp ngay từ đầu: append() là push, và pop() loại bỏ phần tử trên cùng.
my_stack = []
item = 1
my_stack.append(item)
my_stack.pop()
Bằng cách theo dõi vị trí của đỉnh bằng chỉ số, bạn có thể thực hiện các thao tác này nhanh và hiệu quả.
Giải thích khái niệm hàng đợi (queue) và các cách triển khai phổ biến trong Python.
Hàng đợi là cấu trúc vào trước ra trước (FIFO) — giống như xếp hàng ở cửa hàng: người vào ở cuối và ra ở đầu.
Trong Python, bạn có thể triển khai hàng đợi bằng nhiều cách:
Dùng mảng hoặc list và tận dụng các phương thức append() và pop():
my_queue = []
item = 1
# Enqueue
my_queue.append(item)
# Dequeue
my_queue.pop(0)
Dùng deque() từ thư viện collections, thực hiện append() và pop() nhanh hơn list:
from collections import deque
my_queue = deque()
item = 1
# Enqueue
my_queue.append(item)
# Dequeue
my_queue.popleft()
Dùng mô-đun tích hợp sẵn queue.Queue:
from queue import Queue
my_queue = Queue(maxsize = 3)
# Enqueue
my_queue.put(item)
# Dequeue
my_queue.get()
Cây tìm kiếm nhị phân (BST) là gì và hoạt động như thế nào?
Cây nhị phân là một cấu trúc dữ liệu trong đó mỗi nút có tối đa hai con: con trái và con phải. Còn cây tìm kiếm nhị phân (BST) là một loại cây nhị phân cụ thể có các thuộc tính sắp xếp rõ ràng: Đối với mỗi nút, tất cả các khóa ở cây con bên trái nhỏ hơn, tất cả các khóa ở cây con bên phải lớn hơn, và cả hai cây con đều là BST.
Các thuộc tính này giúp thực hiện hiệu quả các thao tác như tìm kiếm, chèn và xóa, thường đạt độ phức tạp thời gian O(log n) trong các cây cân bằng.

Cây tìm kiếm nhị phân. Ảnh: Tác giả.
Giải thích khái niệm băm (hashing) và các ứng dụng.
Băm là kỹ thuật nhận dữ liệu có kích thước bất kỳ và chuyển nó thành một giá trị có kích thước cố định gọi là giá trị băm thông qua một hàm băm.
Một ứng dụng phổ biến của băm là trong bảng băm, nơi nó giúp ánh xạ khóa tới vị trí cụ thể trong mảng, giúp tìm và truy xuất dữ liệu nhanh chóng. Băm có nhiều ứng dụng, từ hỗ trợ bảo mật mật khẩu trong mật mã học đến tổ chức dữ liệu thông qua khử trùng lặp.
Heap là gì và thường dùng để làm gì?
Heap là một cấu trúc dữ liệu giống cây và tuân theo các quy tắc đặc biệt.
Trong max-heap, mỗi nút cha lớn hơn hoặc bằng các nút con; trong min-heap, mỗi nút cha nhỏ hơn hoặc bằng các nút con.
Heap thường được dùng để tạo hàng đợi ưu tiên (priority queue), giúp sắp xếp phần tử theo mức độ quan trọng hoặc giá trị. Chúng cũng quan trọng trong sắp xếp heap (heap sort), một phương pháp tổ chức dữ liệu hiệu quả.

Min-heap là nơi tất cả các nút cha nhỏ hơn các nút con — ảnh: Tác giả.
Câu Hỏi Phỏng Vấn Cấu Trúc Dữ Liệu Trung Cấp
Sau khi đã bao quát phần cơ bản, hãy chuyển sang một số câu hỏi mức trung cấp để khám phá khả năng triển khai và sử dụng các khái niệm nền tảng này của bạn.
Bạn sẽ cân bằng một cây tìm kiếm nhị phân như thế nào?
Một cây tìm kiếm nhị phân cân bằng duy trì chiều cao tương đối đồng đều giữa cây con trái và phải. Cân bằng BST rất quan trọng để giữ cho các thao tác tìm kiếm, chèn và xóa hiệu quả.
Các kỹ thuật như cây AVL và cây đỏ-đen thường được dùng để tự cân bằng. Cây AVL duy trì chênh lệch chiều cao tối đa 1 giữa hai cây con của bất kỳ nút nào, trong khi cây đỏ-đen có các ràng buộc cân bằng chặt chẽ khác.
Bạn sẽ triển khai một min-heap trong Python như thế nào?
Min-heap thường được hỗ trợ bởi một list. Hai thao tác chính là insert (thêm phần tử và đẩy nó lên để khôi phục thuộc tính heap) và extract_min (loại bỏ gốc và sàng xuống để khôi phục trật tự):
class MinHeap:
def __init__(self):
self.heap = []
def __len__(self): # Get the size of the heap
return len(self.heap)
def __parent(self, i): # Get the parent index
return (i - 1) // 2
def __left(self, i): # Get the left child index
return 2 * i + 1
def __right(self, i): # Get the right child index
return 2 * i + 2
def __swap(self, i, j): # Swap two elements
self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
def __heapify_up(self, i): # Restore min-heap property after insertion
while i > 0 and self.heap[i] < self.heap[self.__parent(i)]:
self.__swap(i, self.__parent(i))
i = self.__parent(i)
def __heapify_down(self, i): # Restore min-heap property after extraction
while True:
smallest = i
left = self.__left(i)
right = self.__right(i)
if left < len(self) and self.heap[left] < self.heap[smallest]:
smallest = left
if right < len(self) and self.heap[right] < self.heap[smallest]:
smallest = right
if smallest != i:
self.__swap(i, smallest)
i = smallest
else:
break
def insert(self, val): # Insert a value into the heap
self.heap.append(val)
self.__heapify_up(len(self) - 1)
def extract_min(self): # Extract the minimum value from the heap
if not self.heap:
return None
min_val = self.heap[0]
self.heap[0] = self.heap[-1]
self.heap.pop()
self.__heapify_down(0)
return min_val
Giải thích khái niệm trie và các ứng dụng.
Trie, còn gọi là cây tiền tố (prefix tree), là cấu trúc dữ liệu dạng cây được thiết kế để truy xuất chuỗi và khớp tiền tố hiệu quả.
Trong trie, mỗi nút biểu diễn một ký tự, và các đường đi từ gốc tới các nút tương ứng với các chuỗi hoàn chỉnh. Trie thường được dùng trong tính năng tự động hoàn thành, công cụ kiểm tra chính tả và triển khai từ điển.

Trie, nơi mỗi nút biểu diễn một ký tự kết nối lại để tạo thành chuỗi. Ảnh: Tác giả.
Bạn sẽ triển khai bảng băm có xử lý va chạm như thế nào?
Va chạm xảy ra khi hai khóa khác nhau băm tới cùng một chỉ số.
Có một số phương pháp xử lý va chạm, gồm chaining (xâu chuỗi), trong đó các phần tử va chạm được lưu trong danh sách liên kết tại chỉ số tương ứng; và open addressing (địa chỉ mở), tức là tìm ô trống tiếp theo trong mảng thông qua các phương pháp thăm dò như thăm dò tuyến tính, thăm dò bậc hai hoặc băm kép.
Giải thích khái niệm đồ thị và các cách biểu diễn khác nhau.
Một đồ thị là một cấu trúc dữ liệu gồm tập hợp các đỉnh (nút) được liên kết bởi các cạnh. Cấu trúc này hữu ích để minh họa mối quan hệ và kết nối giữa các thực thể khác nhau.
- Ma trận kề (adjacency matrix). Đây là cách biểu diễn đồ thị bằng một mảng hai chiều. Mỗi phần tử trong mảng cho biết có cạnh giữa hai đỉnh hay không. Nếu bạn nhìn vào hàng của đỉnh i và cột của đỉnh j, giá trị tại đó cho biết có kết nối trực tiếp hay không. Số 0 nghĩa là không kết nối, còn số dương thể hiện trọng số của cạnh.
- Danh sách kề (adjacency list). Trong trường hợp này, dùng một danh sách các danh sách. Mỗi chỉ số trong danh sách chính biểu diễn một đỉnh; các danh sách con thể hiện những đỉnh mà nó kết nối trực tiếp. Cách tổ chức này thường tiết kiệm bộ nhớ hơn ma trận kề, đặc biệt với đồ thị thưa, vì chỉ lưu các kết nối thực tế thay vì mọi khả năng.
Bạn thực hiện duyệt sâu trước (DFS) và duyệt rộng trước (BFS) trên đồ thị như thế nào?
Duyệt sâu trước (DFS) là thuật toán khám phá đồ thị hoặc cây bằng cách đi sâu theo từng nhánh trước khi quay lui. Có thể triển khai bằng ngăn xếp tường minh hoặc đệ quy. Độ phức tạp thời gian là O(V + E), với V là số đỉnh và E là số cạnh, nghĩa là có thể phải duyệt toàn bộ đỉnh và cạnh.
Duyệt rộng trước (BFS) lần lượt khám phá tất cả các nút ở cùng một mức độ sâu trước khi chuyển sang mức tiếp theo. Nó hiệu quả để tìm đường đi ngắn nhất trong đồ thị không trọng số và thường được triển khai bằng hàng đợi. Tương tự DFS, BFS có độ phức tạp O(V + E), cần xem xét tất cả đỉnh và cạnh.
Mô tả các đánh đổi giữa những thuật toán sắp xếp khác nhau.
Các thuật toán sắp xếp rất cần thiết cho xử lý dữ liệu hiệu quả — chúng cho phép tìm kiếm nhanh hơn, phân tích dữ liệu tốt hơn và trực quan hóa dữ liệu dễ dàng hơn. Khi lựa chọn giữa chúng, có một vài đánh đổi chính cần lưu ý:
- Bubble sort dễ triển khai nhưng chậm với đầu vào lớn, độ phức tạp O(n²). Chủ yếu hữu ích cho mục đích giảng dạy.
- Merge sort chạy O(n log n) bất kể đầu vào, nhưng cần thêm bộ nhớ vì tạo mảng tạm trong bước trộn.
- Quick sort cũng trung bình O(n log n) và thường nhanh hơn merge sort trong thực tế vì sắp xếp tại chỗ. Điểm hạn chế là chọn chốt (pivot) kém có thể làm nó tệ nhất O(n²).
Dưới đây là các triển khai Python gọn gàng cho từng thuật toán:
# Bubble sort — sorts in place
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
# Quick sort — sorts in place
def partition(arr, low, high):
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
return i + 1
def quick_sort(arr, low, high):
if low < high:
pi = partition(arr, low, high)
quick_sort(arr, low, pi - 1)
quick_sort(arr, pi + 1, high)
# Merge sort — returns a new sorted list
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left_half = merge_sort(arr[:mid])
right_half = merge_sort(arr[mid:])
return merge(left_half, right_half)
nums = [3, 1, 4, 1, 5, 9, 2, 6]
bubble_sort(nums) # sorts nums in place
quick_sort(nums, 0, len(nums) - 1) # also in place
sorted_nums = merge_sort(nums) # returns a new list
Trong phỏng vấn, câu trả lời trên là đủ. Nhưng nếu bạn muốn nổi bật, hãy nhắc rằng sorted() và list.sort() tích hợp sẵn của Python dùng Timsort, một biến thể lai giữa merge sort và insertion sort. Đó là lý do bạn hầu như không bao giờ viết thuật toán sắp xếp từ đầu trong môi trường Python sản xuất.
Bạn sẽ tiếp cận bài toán tìm đường đi ngắn nhất giữa hai nút trong đồ thị như thế nào?
Có nhiều thuật toán để tìm đường đi ngắn nhất trong đồ thị.
Với đồ thị không trọng số, duyệt rộng trước khám phá các nút theo từng lớp rất hiệu quả. Trong đồ thị có trọng số với cạnh không âm, thuật toán Dijkstra xác định đường đi ngắn nhất bằng cách xét trước đỉnh gần nhất.
Thuật toán A* cải thiện hiệu quả bằng cách dùng heuristic để ước lượng chi phí còn lại. Việc chọn thuật toán phụ thuộc vào đặc điểm đồ thị và yêu cầu bài toán cụ thể.
Câu Hỏi Phỏng Vấn Cấu Trúc Dữ Liệu Nâng Cao
Hãy khám phá một số câu hỏi nâng cao dành cho ứng viên nhắm tới vị trí cấp cao hoặc muốn thể hiện hiểu biết sâu về các cấu trúc dữ liệu chuyên biệt hay phức tạp.
Giải thích khái niệm lập trình động (dynamic programming) và cách áp dụng để giải các bài toán liên quan đến cấu trúc dữ liệu.
Lập trình động là phương pháp giải bài toán phức tạp bằng cách chia chúng thành các bài toán con chồng lặp nhỏ hơn. Thay vì làm lại từ đầu mỗi lần, bạn lưu lời giải của các phần nhỏ đó, giúp tránh lặp lại tính toán.
Phương pháp này rất hữu ích để tìm dãy con chung dài nhất giữa hai chuỗi hoặc tìm chi phí tối thiểu để tới một điểm cụ thể trên lưới.
Giải thích khái niệm B-tree và ưu điểm của nó so với cây tìm kiếm nhị phân.
B-tree là cấu trúc dữ liệu cây cân bằng được thiết kế để truy cập đĩa hiệu quả. Một số đặc điểm:
- Tất cả các lá có cùng độ sâu.
- Mỗi nút chứa số lượng khóa biến thiên trong một phạm vi xác định.
- Các nút bên trong đóng vai trò như cấu trúc chỉ mục, dẫn hướng tìm kiếm tới cây con phù hợp.
Chúng mang lại nhiều ưu điểm so với cây tìm kiếm nhị phân:
- Giảm I/O đĩa: Nhiều khóa có thể được lưu trong mỗi nút, giảm số lần đọc đĩa cần thiết để tìm một khóa cụ thể.
- Hiệu năng cải thiện: Với tập dữ liệu lớn, khả năng chứa nhiều khóa mỗi nút giúp giảm số tầng của cây và tăng tốc tìm kiếm.
Mô tả khái niệm sắp xếp topo và các ứng dụng.
Sắp xếp topo là thuật toán dùng để sắp thứ tự các đỉnh của một đồ thị có hướng không chu trình (DAG) sao cho nếu có cạnh từ đỉnh u tới đỉnh v thì u xuất hiện trước v trong thứ tự. Thuật toán này thường dùng trong lập lịch tác vụ — xác định thứ tự chạy các tác vụ để tôn trọng phụ thuộc — cũng như trong hệ thống build, trình quản lý gói, và lập kế hoạch học phần có học phần tiên quyết.
Phân biệt giữa min-heap và hàng đợi ưu tiên (priority queue).
Một min-heap là một cách triển khai cụ thể của hàng đợi ưu tiên, được định nghĩa là một cây nhị phân đầy đủ trong đó giá trị của mỗi nút không lớn hơn giá trị các nút con, cho phép tìm và trích xuất phần tử nhỏ nhất hiệu quả.
Ngược lại, hàng đợi ưu tiên là một cấu trúc dữ liệu trừu tượng cho phép chèn phần tử kèm mức ưu tiên, và các phần tử được lấy ra theo thứ tự ưu tiên. Min-heap là cách triển khai phổ biến cho hàng đợi ưu tiên nhờ khả năng xử lý các thao tác này hiệu quả.
Giải thích cấu trúc dữ liệu tập rời (disjoint-set) và các ứng dụng.
Cấu trúc dữ liệu tập rời, còn gọi là union-find, duy trì một tập hợp các tập rời nhau. Cấu trúc này hỗ trợ hai thao tác chính:
- Find: Xác định một phần tử thuộc tập nào.
- Union: Hợp nhất hai tập thành một tập.
Có nhiều ứng dụng của tập rời, nhưng phổ biến nhất là thuật toán Kruskal để tìm cây khung nhỏ nhất của đồ thị và bài toán luồng mạng để xác định các thành phần liên thông trong đồ thị.
Giải thích khái niệm cây đoạn (segment tree) và các ứng dụng.
Cây đoạn là cấu trúc dữ liệu được thiết kế để hỗ trợ hiệu quả các truy vấn theo khoảng và cập nhật trên một mảng. Nó đặc biệt hữu ích trong các tình huống cần lặp đi lặp lại các phép như tính tổng, giá trị nhỏ nhất, lớn nhất, hoặc ước số chung lớn nhất trên một khoảng phần tử cụ thể của mảng.
Cấu trúc này được xây dựng như một cây nhị phân, trong đó mỗi nút biểu diễn một đoạn của mảng. Các lá tương ứng với từng phần tử của mảng, trong khi các nút bên trong lưu thông tin tổng hợp từ các nút con theo phép toán đang thực hiện. Chúng đạt độ phức tạp O(log n) cho cả cập nhật và truy vấn.
Bạn sẽ triển khai cây hậu tố (suffix tree) như thế nào?
Cây hậu tố lưu mọi hậu tố của một chuỗi để truy vấn mẫu có thời gian tỉ lệ với độ dài mẫu, không phụ thuộc độ dài văn bản. Cây hậu tố “đúng nghĩa” dùng nén cạnh để đạt O(n) bộ nhớ và thường được xây bằng thuật toán Ukkonen — nhưng điều đó đủ phức tạp để người phỏng vấn hiếm khi kỳ vọng bạn mã hóa từ đầu trong 45 phút.
Một thỏa hiệp phổ biến là trie hậu tố đơn giản hơn, lưu một ký tự mỗi nút. Nó dùng O(n²) bộ nhớ nhưng dễ viết và giải thích hơn nhiều. Mẹo trong phỏng vấn là hiểu rõ đánh đổi và nói ra điều đó một cách rõ ràng.
Dưới đây là một triển khai Python gọn gàng:
class SuffixTrieNode:
def __init__(self):
self.children = {} # Map of character -> child node
self.indices = [] # Starting positions of suffixes passing through this node
class SuffixTrie:
def __init__(self, text):
self.root = SuffixTrieNode()
self.text = text + "$" # Append a unique terminator
self._build()
def _build(self):
"""Insert every suffix of the text into the trie."""
for i in range(len(self.text)):
self._insert_suffix(i)
def _insert_suffix(self, index):
node = self.root
for i in range(index, len(self.text)):
c = self.text[i]
if c not in node.children:
node.children[c] = SuffixTrieNode()
node = node.children[c]
node.indices.append(index)
def search(self, pattern):
"""Return all starting positions where `pattern` appears in the text."""
node = self.root
for c in pattern:
if c not in node.children:
return []
node = node.children[c]
return node.indices
Quadtree là gì và ứng dụng phổ biến nhất của chúng là gì?
Quadtree là cấu trúc dữ liệu cây phân cấp, đệ quy chia không gian hai chiều thành bốn phần tư bằng nhau. Kỹ thuật phân vùng không gian này rất hiệu quả cho các ứng dụng như xử lý ảnh, phát hiện va chạm trong trò chơi, và hệ thống thông tin địa lý để lưu trữ và truy xuất dữ liệu không gian hiệu quả.
Câu Hỏi Phỏng Vấn Cấu Trúc Dữ Liệu Theo Tình Huống
Thể hiện kiến thức về cấu trúc dữ liệu là quan trọng, nhưng chứng minh rằng bạn biết dùng chúng đúng lúc đúng chỗ sẽ giúp bạn nổi bật trong buổi phỏng vấn. Trong phần này, chúng ta sẽ xem cách áp dụng kiến thức cấu trúc dữ liệu vào các tình huống thực tiễn.
Bạn đang thiết kế hệ thống cho dịch vụ gọi xe. Cấu trúc dữ liệu nào có thể ghép tài xế với hành khách?
Do tính chất thời gian thực, thách thức này đòi hỏi các cấu trúc dữ liệu hiệu quả.
Theo kinh nghiệm của tôi, tôi sẽ dùng quadtree cho dữ liệu địa lý, hàng đợi ưu tiên để xếp hạng các ghép đôi tiềm năng dựa trên khoảng cách và mức độ khẩn cấp của hành khách, và bảng băm để tra cứu nhanh vị trí tài xế và hành khách.
Bạn sẽ dùng cấu trúc dữ liệu nào để gợi ý sản phẩm cho người dùng dựa trên hành vi trong quá khứ?
Chúng ta có thể kết hợp nhiều cấu trúc dữ liệu để gợi ý sản phẩm hiệu quả dựa trên hành vi người dùng.
Ma trận thưa user-item sẽ lưu tương tác người dùng - sản phẩm, trong khi bảng băm ánh xạ hiệu quả người dùng và sản phẩm. Hàng đợi ưu tiên xếp hạng gợi ý, và cấu trúc đồ thị có thể mô hình hóa quan hệ người dùng - sản phẩm cho các phân tích nâng cao như phát hiện cộng đồng.
Bạn làm việc cho một nền tảng mạng xã hội. Cấu trúc dữ liệu nào giúp phát hiện và loại bỏ tài khoản spam?
Cấu trúc dữ liệu đồ thị có thể rất hiệu quả để phát hiện và loại bỏ tài khoản spam trên nền tảng mạng xã hội. Bằng cách biểu diễn người dùng là nút và kết nối của họ là cạnh, bạn có thể phân tích tô-pô mạng. Việc xác định các cụm dày đặc, nút cô lập và đột biến hoạt động đột ngột có thể giúp gắn cờ các tài khoản đáng ngờ.
Bạn sẽ dùng cấu trúc dữ liệu nào để phân phối tin nhắn tới đúng người nhận trong một ứng dụng chat thời gian thực?
Tôi sẽ dùng kết hợp nhiều cấu trúc dữ liệu trong một ứng dụng chat thời gian thực.
Bảng băm sẽ lưu ID người dùng và danh sách kết nối tương ứng, cho phép tra cứu nhanh người dùng để gửi tin nhắn. Hàng đợi sẽ được triển khai cho mỗi người dùng để duy trì thứ tự tin nhắn, đảm bảo chúng được gửi theo trình tự. Ngoài ra, cây, như cây AVL, có thể dùng để lưu và truy xuất trạng thái online/offline hiệu quả, cho phép cập nhật thời gian thực về tình trạng sẵn sàng của người dùng.
Bạn đang xây dựng bộ kiểm tra chính tả cho một ứng dụng soạn thảo văn bản. Bạn sẽ dùng cấu trúc dữ liệu nào để lưu và tìm kiếm từ hợp lệ trong từ điển một cách hiệu quả?
Với bộ kiểm tra chính tả, tra cứu từ hiệu quả là rất quan trọng. Trie sẽ là cấu trúc dữ liệu lý tưởng. Mỗi nút trong trie biểu diễn một chữ cái, và các đường đi qua trie tạo thành từ. Điều này cho phép tìm kiếm theo tiền tố nhanh, giúp bộ kiểm tra chính tả đề xuất sửa lỗi cho từ sai một cách nhanh chóng.
Bạn sẽ dùng cấu trúc dữ liệu nào để thiết kế hệ thống cho trò chơi chiến lược thời gian thực xử lý truy vấn theo vùng cho công trình và cập nhật khi có tòa nhà mới?
Trong tình huống này, cây đoạn là lựa chọn nổi bật. Chúng rất giỏi xử lý truy vấn theo khoảng và cập nhật hiệu quả. Ta có thể biểu diễn bản đồ trò chơi dưới dạng mảng 1D, mỗi phần tử tương ứng một ô lưới. Mỗi ô có thể lưu thông tin về sự hiện diện hay vắng mặt của một công trình.
Mẹo Chuẩn Bị Cho Phỏng Vấn Cấu Trúc Dữ Liệu
Tôi hiểu rằng chuẩn bị cho phỏng vấn cấu trúc dữ liệu có thể là thách thức, nhưng một cách tiếp cận có cấu trúc sẽ giúp bạn thấy dễ dàng hơn!
Tập trung nắm vững các khái niệm nền tảng của cấu trúc dữ liệu như mảng, danh sách liên kết, ngăn xếp, hàng đợi, cây, đồ thị và bảng băm. Hiểu nguyên lý của chúng, cách quản lý dữ liệu và độ phức tạp thời gian của các thao tác như chèn, xóa và tìm kiếm.
Biết khái niệm là tốt nhưng chưa đủ. Bạn nên biết cách tự triển khai các cấu trúc dữ liệu này từ đầu. Bạn có thể tham gia các khóa học DataCamp để tận dụng các thử thách mã hóa giúp mài giũa kỹ năng giải quyết vấn đề.
Hiểu các đánh đổi giữa các cấu trúc dữ liệu là chìa khóa. Ví dụ, mảng cho phép truy cập nhanh nhưng tốn kém khi chèn và xóa, trong khi danh sách liên kết cho phép chỉnh sửa hiệu quả nhưng cần duyệt để truy cập. Hãy sẵn sàng thảo luận các đánh đổi này trong buổi phỏng vấn.
Hãy nhớ, giao tiếp cũng quan trọng như mã. Người phỏng vấn tìm kiếm ứng viên có thể điều chỉnh cách giải thích phù hợp với đối tượng. Như đã bàn trong podcast DataFramed về tương lai của các vai trò dữ liệu:
Bạn cần có khả năng truyền đạt mọi loại insight theo cách mà một đứa trẻ sáu tuổi cũng hiểu được và đồng thời làm hài lòng tôi hoặc thậm chí cả những người còn kỹ thuật hơn nữa. Vậy nên nếu bạn thực sự nắm vững vấn đề, bạn có thể diễn giải thật đơn giản, nhưng cũng có thể làm nó phức tạp đến mức, thực lòng mà nói, chỉ những người thực sự, thực sự xuất sắc về chuyên môn kỹ thuật mới hiểu được.
Mo Chen, Data & Analytics Manager at NatWest Group
Cuối cùng, hãy kết nối kiến thức của bạn với các ứng dụng thực tế. Hãy cân nhắc cách bạn có thể dùng các cấu trúc dữ liệu, như những gì chúng ta đã khám phá trong bài viết này, trong phát triển web, hệ quản trị cơ sở dữ liệu hoặc học máy.
Kết luận
30 câu hỏi này bao quát các cấu trúc dữ liệu và thuật toán thường xuất hiện nhất trong phỏng vấn kỹ thuật — từ mảng và danh sách liên kết đến đồ thị, sắp xếp, và các cấu trúc nâng cao giúp phân biệt ứng viên cấp cao. Cách nhanh nhất để ghi nhớ là tự triển khai từng cấu trúc từ đầu và giải thích to thành lời.
Nếu bạn cần luyện tập thêm về cấu trúc dữ liệu cho buổi phỏng vấn, hãy xem các khóa học và blog sau:
