2012-01-23 31 views
6

Gần đây tôi đã tham gia một cuộc phỏng vấn nơi họ hỏi tôi những câu hỏi kỹ thuật. Một là cách bạn sẽ tính số nào trong danh sách độ dài n-1 bị thiếu. Danh sách chứa tất cả các số từ 1 đến n, ngoại trừ i trong đó 1 < = i < = n. Các con số không theo thứ tự. Giải pháp của tôi là cộng tất cả chúng lên, sau đó trừ đi từ việc tính toán các số từ 1 đến n, bằng cách thêm 1 đến n và nhân với n/2 hoặc (n-1)/2 khi thích hợp. Nhưng tôi có cảm giác rằng có một cách tốt hơn để làm điều đó. Giải pháp tối ưu là gì?Cách tối ưu để tính số nguyên nào trong danh sách bị thiếu?

+0

Hãy xem xét phạm vi sẽ trông như thế nào nếu bạn sắp xếp nó. Nếu bạn có thể nghĩ ra một từ bắt đầu bằng chữ "P" bạn đang đi đúng hướng. –

+0

Nhưng sẽ không phân loại nó đòi hỏi nhiều công việc hơn so với phương pháp của tôi? (Và tôi xin lỗi, tôi không thể nghĩ ra từ) – CSturgess

+0

Tôi không nói rằng phân loại là câu trả lời, chỉ cần bạn nên suy nghĩ về những gì nó sẽ như thế nào. Chữ thứ hai là "e". –

Trả lời

4

Câu trả lời của bạn là đủ tốt, theo ý kiến ​​của tôi.

Nhưng một số người - có lẽ người phỏng vấn của bạn là một trong số họ - đang lo lắng về tình trạng tràn và như vậy. Trong trường hợp đó, hãy sử dụng XOR thay vì bổ sung.

Để lấy XOR của các số nguyên từ 0 đến n, chỉ cần XOR cùng với các chỉ mục mảng khi bạn lặp lại. Với XOR của các số nguyên từ 0 đến n và XOR của các phần tử mảng, bạn chỉ XOR hai số nguyên tố đó lại với nhau để lấy phần tử còn thiếu.

P.S. Tổng các số nguyên từ 1 đến n luôn là (n + 1) * n/2

+0

Tôi thích lừa XOR của bạn! Tuy nhiên, điều thú vị là bạn không cần phải lo lắng về tràn để giải quyết vấn đề, miễn là bạn biết rằng hệ thống của bạn giữ các bit thấp hơn chính xác của kết quả. trừ tổng số được tính toán (tràn) của các số từ tổng (cũng bị tràn) được tính bằng phương pháp Gaussian, và đáng ngạc nhiên, bạn sẽ nhận được số! Bí quyết sẽ không hoạt động nếu hệ thống luôn kiểm tra tràn số nguyên (ví dụ: Ada). Nó cũng sẽ không hoạt động trên phao nổi, nhưng cũng không phải là thủ thuật XOR. XOR lừa đòi hỏi một vượt qua mảng, trừ khi có một công thức khép kín như một cho tổng hợp. – kkm

+0

@kkm: Phương pháp Gaussian chỉ tránh được vấn đề tràn nếu bạn tính toán (n/2) hoặc (n + 1)/2 trước (tùy theo số nào là số nguyên). Nếu bạn nhân n bằng n + 1, bạn bị mất bit cao và không thể lấy lại nó khi bạn chia cho 2. Nhưng có, khác hơn thế, làm tổng modulo 2^k hoạt động tốt. – Nemo

0

trong khi lặp qua mảng để tính tổng, bạn có thể kiểm tra xem liệu một số có lặp lại hay không.

+0

Bạn có thể mở rộng trên đó, tôi không thể nhìn thấy những gì bạn có ý nghĩa. – CSturgess

+0

trong câu trả lời của bạn, bạn đã đề cập rằng giải pháp có thể được tính toán thông qua tính tổng và sau đó trừ nó khỏi tổng số. để tính tổng, bạn phải lặp lại suy nghĩ mảng. – KItis

+1

Có, nhưng ý bạn là lặp lại điều gì? Các con số không lặp lại. – CSturgess

0

Phương pháp của bạn hoàn toàn ổn. Nó là tối ưu cả về không gian và thời gian. Tràn có thể là vấn đề duy nhất với nó.

Một phương pháp khác có thể là sử dụng hàm băm. Tạo một hashSet ban đầu có các giá trị 1-> N. Bây giờ cho mỗi số bạn gặp phải trong danh sách - xóa giá trị đó khỏi hashSet. Cuối cùng, giá trị còn lại trong hashSet là giá trị bị thiếu.

Phương pháp này là O (N) về thời gian và không gian phức tạp. Phương pháp của bạn (chặn tràn) là O (N) trong thời gian và O (1) phức tạp. Yếu tố 'n' được thêm vào cho không gian là chi phí để loại bỏ tràn.

0

giải pháp của bạn là khá nhiều tối ưu với một thay đổi, như @Nemo chỉ ra tổng của các số nguyên từ 1 đến n luôn là (n+1) * n/2

Nó cũng có giá trị chỉ ra rằng cách tiếp cận của bạn là multi-thread có khả năng (và might phù hợp với các giá trị rất lớn của N), chia mảng thành từng phần, sau đó lấy tổng của mỗi phần mảng trong một chuỗi, sau đó thêm các phần tiền đó. Nó phụ thuộc vào chi phí của luồng được so sánh với việc thêm số vào một mảng.

Nếu bạn lo lắng về việc tràn và giá trị luôn luôn là int32 (như hầu hết các giá trị .Length bao gồm mảng) thì chỉ lưu trữ tổng dưới dạng int64, tổng của tất cả các giá trị nguyên dương (((long)int.MaxValue) +1L) * (int.MaxValue/2) = 2305843007066210304. trong một int64 với .MaxValue = 9223372036854775807.

Câu trả lời khác như được đề cập bởi những người khác là XOR từng mục và giữ một XOR đang chạy, nhưng sau đó bạn cần phải tính toán công thức để đạt được tổng XOR dự kiến ​​trong thời gian O(1).

Rất có thể người phỏng vấn đang tìm cách xem bạn có nhận được giải pháp O(N) với bộ nhớ O(1) (câu trả lời của bạn) thay vì sắp xếp mảng và chậm hơn nhiều cho các giá trị rất lớn là N.

Để cải thiện hơn nữa giải pháp của bạn trong mã, sẽ sử dụng con trỏ để truy cập mảng thay vì giá trị chỉ mục (nếu mã của bạn là C# sẽ là một cải tiến hợp lý).

Các vấn đề liên quan