Một trong những câu hỏi phổ biến nhất từ cấu trúc dữ liệu và thuật toán, chủ yếu được hỏi về phỏng vấn qua điện thoại.
Một trong những câu hỏi phổ biến nhất từ cấu trúc dữ liệu và thuật toán, chủ yếu được hỏi về phỏng vấn qua điện thoại.
Câu trả lời:
Bằng cách gian lận, và thực hiện hai đường chuyền cùng một lúc, song song. Nhưng tôi không biết liệu các nhà tuyển dụng sẽ thích điều này.
Có thể được thực hiện trên một danh sách liên kết duy nhất, với một mẹo hay. Hai con trỏ đi qua danh sách, một với tốc độ gấp đôi. Khi cái nhanh đến cuối cùng, cái kia là một nửa.
Nếu đó không phải là danh sách được liên kết đôi, bạn chỉ có thể đếm và sử dụng danh sách, nhưng điều đó đòi hỏi phải tăng gấp đôi bộ nhớ của bạn trong trường hợp xấu nhất và đơn giản là nó sẽ không hoạt động nếu danh sách quá lớn để lưu trữ trong bộ nhớ.
Một giải pháp đơn giản, gần như ngớ ngẩn, chỉ là tăng nút giữa mỗi hai nút
function middle(start) {
var middle = start
var nextnode = start
var do_increment = false;
while (nextnode.next != null) {
if (do_increment) {
middle = middle.next;
}
do_increment = !do_increment;
nextnode = nextnode.next;
}
return middle;
}
Xây dựng câu trả lời của Hendrik
Nếu đó là một danh sách liên kết đôi, lặp đi lặp lại từ cả hai đầu
function middle(start, end) {
do_advance_start = false;
while(start !== end && start && end) {
if (do_advance_start) {
start = start.next
}
else {
end = end.prev
}
do_advance_start = !do_advance_start
}
return (start === end) ? start : null;
}
Được [1, 2, 3] => 2
1, 3
1, 2
2, 2
Được [1, 2] => 1
1, 2
1, 1
Được [1] => 1
Được [] => null
Tạo một mảng động, trong đó mỗi phần tử của mảng là một con trỏ tới mỗi nút trong danh sách theo thứ tự di chuyển ngang, bắt đầu từ đầu. Tạo một số nguyên, được khởi tạo thành 1, theo dõi số lượng nút bạn đã truy cập (tăng theo mỗi lần bạn đến một nút mới). Khi bạn đi đến cuối, bạn sẽ biết danh sách này lớn như thế nào và bạn có một mảng các con trỏ theo thứ tự cho mỗi nút. Cuối cùng, chia kích thước của danh sách cho 2 (và trừ 1 cho lập chỉ mục dựa trên 0) và tìm nạp con trỏ được giữ trong chỉ mục đó của mảng; nếu kích thước của danh sách là số lẻ, bạn có thể chọn phần tử nào sẽ trả về (tôi vẫn sẽ trả về phần tử đầu tiên).
Đây là một số mã Java có điểm nhấn (mặc dù ý tưởng về một mảng động sẽ hơi phức tạp). Tôi sẽ cung cấp C / C ++ nhưng tôi rất gỉ trong khu vực đó.
public Node getMiddleNode(List<Node> nodes){
int size = 1;
//add code to dynamically increase size if at capacity after adding
Node[] pointers = new Node[10];
for (int i = 0; i < nodes.size(); i++){
//remember to dynamically allocate more space if needed
pointers[i] = nodes.get(i);
size++;
}
return pointers[(size - 1)/2];
}
Là đệ quy được xem xét nhiều hơn một vượt qua?
Di chuyển danh sách đến cuối, chuyển một số nguyên theo tham chiếu. Tạo một bản sao cục bộ của giá trị đó ở mỗi cấp để tham chiếu sau và tăng số lượng ref sẽ được thực hiện trong cuộc gọi tiếp theo.
Trên nút cuối cùng, chia số đếm cho hai và cắt bớt / sàn () kết quả (nếu bạn muốn nút đầu tiên là "giữa" khi chỉ có hai phần tử) hoặc làm tròn (nếu bạn muốn nút thứ hai là "giữa"). Sử dụng một chỉ số không hoặc một dựa trên một cách thích hợp.
Unwinding, khớp số đếm ref với bản sao cục bộ (là số của nút). Nếu bằng nhau, trả lại nút đó; khác trả về nút trả về từ cuộc gọi đệ quy.
.
Có nhiều cách khác để làm điều này; một số trong số chúng có thể ít cồng kềnh hơn (tôi nghĩ rằng tôi đã thấy ai đó nói đọc nó thành một mảng và sử dụng chiều dài mảng để xác định kudos giữa). Nhưng thành thật mà nói, không có câu trả lời tốt, bởi vì đó là một câu hỏi phỏng vấn ngu ngốc. Số một, những người vẫn sử dụng danh sách liên kết ( ý kiến hỗ trợ ); Hai, tìm nút giữa là một bài tập học thuật tùy tiện, không có giá trị trong các tình huống thực tế; Thứ ba, nếu tôi thực sự cần biết nút giữa, danh sách được liên kết của tôi sẽ hiển thị số lượng nút. Thật dễ dàng để duy trì tài sản đó hơn là lãng phí thời gian đi qua toàn bộ danh sách mỗi khi tôi muốn nút giữa. Và cuối cùng, bốn, mọi người phỏng vấn sẽ thích hoặc từ chối các câu trả lời khác nhau - điều mà một người phỏng vấn nghĩ là lắt léo, người khác sẽ gọi là vô lý.
Tôi hầu như luôn trả lời các câu hỏi phỏng vấn với nhiều câu hỏi hơn. Nếu tôi nhận được một câu hỏi như thế này (tôi không bao giờ có), tôi sẽ hỏi (1) Bạn đang lưu trữ gì trong danh sách được liên kết này và có cấu trúc phù hợp hơn để truy cập hiệu quả vào nút giữa nếu thực sự cần phải làm như vậy ; (2) Những hạn chế của tôi là gì? Tôi có thể làm cho nó nhanh hơn nếu bộ nhớ không phải là một vấn đề (ví dụ như câu trả lời mảng), nhưng nếu người phỏng vấn nghĩ rằng bộ nhớ bị phồng lên là lãng phí, tôi sẽ bị chìm. (3) Tôi sẽ phát triển ngôn ngữ nào? Gần như mọi ngôn ngữ hiện đại mà tôi biết đều có các lớp dựng sẵn để đối phó với các danh sách được liên kết khiến việc duyệt qua danh sách trở nên không cần thiết - tại sao lại phát minh ra thứ gì đó đã được các nhà phát triển ngôn ngữ điều chỉnh để đạt hiệu quả?
Bằng cách sử dụng 2 con trỏ. Tăng một lần ở mỗi lần lặp và lần khác ở mỗi lần lặp thứ hai. Khi con trỏ thứ 1 trỏ đến cuối danh sách được liên kết, con trỏ thứ 2 sẽ trỏ đến chế độ giữa của danh sách được liên kết.