Các câu hỏi phỏng vấn [1]

Microsoft nổi tiếng là có các câu hỏi phỏng vấn nhân viên mới mang tính kỹ thuật theo dạng đố “mẹo” (đa số là về thuật toán hoặc lập trình C/C++). Có nhiều bộ sưu tập các câu hỏi dạng này đã từng được hỏi ở các cuộc phỏng vấn ở Microsoft. Gần đây Google cũng phỏng vấn theo kiểu tương tự. Mỗi câu trả lời chỉ được cho khoảng 5-10 phút suy nghĩ. Đôi khi người ta quan tâm đến quá trình suy nghĩ của bạn hơn là bản thân câu trả lời.

Trong chuỗi bài này tôi sẽ nêu chọn lọc một số câu hỏi tôi thích nhất. Các câu hỏi được chọn không nhất thiết là khó nhất, tiêu chuẩn là gọn gàng và đẹp.

  1. Cho một danh sách liên kết đơn (simple linked list) hữu hạn. Có hai trường hợp: một là cuối danh sách trỏ về NULL, hai là trỏ về một phần tử đã gặp – tạo nên một vòng tròn trong danh sách.
    Ví dụ trường hợp 1: A –> B –> C –> D –> NULL.
    Ví dụ trường hợp 2: A –> B –> C –> D –> E –> F –> C.
    Cho trước một con trỏ vào một danh sách liên kết đơn L nào đó, hữu hạn nhưng có thể có độ dài tùy ý. Làm thế nào để kiểm tra nhanh nhất nếu danh sách L thuộc trường hợp 1 hay trường hợp 2, với điều kiện là ta chỉ được dùng vài chục bytes bộ nhớ.
  2. Cho một chuỗi ký tự s bao gồm nhiều từ. Viết một đoạn chương trình C đảo thứ tự các từ.
    Ví dụ: với input là “this is a nice blog” thì output là “blog nice a is this“.
  3. Cho hai dãy số đã xếp thứ tự tăng dần AB, mỗi dãy có n phần tử. Xét tập hợp sau:
    S = { A[i] + B[j] | 1 < = i, j <= n }.
    Chú ý rằng S có thể có đến n2 phần tử. Viết một chương trình in ra n số lớn nhất trong S. Chương trình phải chạy trong thời gian O(n).

Chủ đề : Dành cho du học sinh, Vui - Giải Trí. Bookmark the permalink. Trackbacks are closed, but you can post a comment.

9 Comments

  1. Phan Duy Hùng
    Posted 16/11/2008 at 2:26 am | Permalink

    Hôm nay em được biết đến các câu hỏi phỏng vấn này, suy nghĩ mãi xin nêu ra cách giải tạm chấp nhận được cho bài 1:
    Lưu lại vị trí bắt đầu Linked List, sau đó duyệt list, khi duyệt tới node nào thì đảo chiều liên kết của nó lại: A->B thì B->A
    nếu node của chúng ta là null –> Linked List loại 1
    nếu node của chúng ta trở về vị trí bắt đầu: Linked List loại 2, lúc này ta lại duyệt Linked List 1 lần nữa theo cách duyệt như vậy sẽ cho trở lại Linked List ban đầu

    Mong anh Hưng và các bạn chỉ bảo cách nhanh nhất để thực hiện yêu cầu trên

  2. Posted 19/11/2008 at 10:26 am | Permalink

    Chào Hùng,

    Cách giải rất hay! Về asymptotic thì không có cách nào nhanh hơn (đều cần O(n) bước). Nhưng, có cách không cần phải “sửa” bất kỳ link nào trong link list cả.

  3. donnghi
    Posted 11/07/2009 at 11:52 am | Permalink

    Hi thầy Hưng (do em không biết dùng từ nào phù hợp hơn ^^),

    Bài 1.Ta có thể thấy, nếu rơi vào trường hợp 1 và list đủ dài thì dù ta nhanh tới mấy thì thời gian cũng không thể chấp nhận được (và do đó không biết thuộc TH1 hay TH2), do đó em định cận là thời gian hợp lý phụ thuộc vào tốc độ tính toán, nếu quá thời gian mà không tìm ra NULL thì dừng và quyết định thuộc trường hợp 2, nếu tìm ra NULL thì hiển nhiên là trường hợp 1.

    Bài 2.Bài này em chia làm hai giai đoạn: giai đoạn 1 em đơn thuần đảo toàn bộ xâu, trong ví dụ thì xâu trở thành: « golb ecin a si siht ». Giai đoạn 2 em đọc từng từ vào một biến tạm rồi đảo từng từ đọc được sau đó ghép vào một xâu chung, ví dụ đọc xong từ « golb » em sẽ đảo thành « blog » rồi ghép vào đầu xâu. Làm tiếp tục em sẽ có kết quả.

    Bài 3.Bài này ngoài hai mảng A và B lưu mảng được sắp của đầu bài, em dùng thêm một mảng, mảng C chẳng hạn với ý nghĩa: C[i] lưu chỉ số j sao cho A[i] + B[j] là kết quả nếu ta chọn A[i].
    Khởi tạo: C[i] = 1 với mọi i (A[1] lớn nhất, sau đó là A[2], …)
    Giả sử ta đang xét A[i], ta so sánh tổng A[i] + B[C[i]] với A[i + 1] + B[C[i + 1]] và A[i – 1] + B[C[i – 1]]. Ta có 3 trường hợp xảy ra:
    TH1.Tổng A[i] + B[C[i]] lớn nhất, ta in tổng và tăng C[i + 1].
    TH2.Tổng A[i + 1] + B[C[i + 1]] lớn nhất, ta in tổng và tăng C[i + 1], đồng thời chuyển xuống xét vị trí i + 1.
    TH3.Tổng A[i – 1] + B[C[i – 1]] lớn nhất, ta in tổng và tăng C[i - 1], đồng thời chuyển con trỏ lên vị trí i – 1.
    Ta cần lưu ý giá trị cận như i – 1 vượt mảng, còn giá trị mảng C thì không cần.
    Độ phức tạp: O( 2n ).

  4. pl
    Posted 11/07/2009 at 10:10 pm | Permalink

    bạn donnghi thử dùm mình cái test này nhá
    A: 10 9 8 7 -100
    B: 100 10 10 10 10

  5. donnghi
    Posted 12/07/2009 at 6:15 am | Permalink

    Cảm ơn bạn đã tìm ra lỗi của giải thuật, trong TH3 ta chưa in kết quả và bổ sung một vòng lặp kiểm tra điều kiện leo lên trong khi vẫn phát hiện ra giá trị lớn nhất là i – 1.

    Độ phức tạp O( 2n ).

  6. Clairsang
    Posted 31/10/2010 at 2:24 pm | Permalink

    Mình có cuốn Cracking The Coding Interview 4ed, bản đẹp. Bạn nào thích thì gửi email vào clairsang@gmail.com mình sẽ reply đính kèm.

  7. Phuc Nguyen
    Posted 24/03/2011 at 5:21 am | Permalink

    Hi thầy Hưng.

    Hôm nay em đọc bài này, thấy câu 1 chưa ai giải nên em comment luôn. Cách giải ko phải do em nghĩ ra, nên ko biết có… vô duyên quá ko :D

    Trong cuốn Elements of Programming có 1 chương về Transformations với Orbits. Trong đó có thuật toán (tổng quát hơn tí xíu) để xét coi chu kỳ của 1 hàm kết thúc hay lẩn quẩn. Thuật toán sẽ dừng nếu chu kỳ hữu hạn.

    Nôm na là như vầy: Cho 2 biến lần lần theo giá trị trong danh sách. Biến A mỗi lần đi 2 bước, biến B mỗi lần đi 1 bước. Nếu danh sách ko có vòng thì biến A luôn đi nhanh hơn và cuối cùng sẽ đụng NULL trước. Nếu danh sách có vòng, sẽ đến lúc cả 2 biến A và B cùng vào vòng. Vì A đi nhanh hơn 1 bước nên sau mỗi bước lặp, khoảng cách giữa 2 biến sẽ giảm 1, tức là chắc chắn có lúc A=B.

    • pjthon
      Posted 24/03/2011 at 10:05 am | Permalink

      @Phuc Nguyen: hi, cách giải bạn nói gọn thật, complexity O(n) (A=B, ý bạn chắc so sánh addresses của hai biến?). Nhưng sao không thấy cần dùng đến “vài chục bytes” bộ nhớ như anh Hưng nói nhỉ.

      Trước đó em mới nghĩ được cách với complexity O(n \log n), n là độ dài thật sự của list. Ngoài ra nếu n = 2^{100} thì cần đến những 100 * 4 = 400 Bytes bộ nhớ :D (giải sử address 4 bytes)
      Cách của em như này: list X lưu addresses của các elements có index 2^i trong quá trình duyệt list. Nếu gặp NULL thì là list loại 1. Với mỗi element khác NULL của list, check xem address của element này có trong list X chưa. Nếu có rồi thì là list loại 2.

    • Posted 24/03/2011 at 11:32 am | Permalink

      Lời giải Phuc Nguyen ghi là chính xác rồi!

      @Pjthon, tôi viết “vài chục bytes” thật ra ý là tổng bộ nhớ ta cần không phụ thuộc vào n.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>