Giải pháp 65 byte trước đó:
r->{for(int a,b=0,z,i=0;;b=a)if((a=b|1<<(z=r[i++]))==b)return z;}
Giải pháp mới. 19 byte được bao gồm choimport java.math.*;
-8 byte nhờ @Nevay
r->{int z,i=0;for(BigInteger c=BigInteger.ZERO;c.min(c=c.setBit(z=r[i++]))!=c;);return z;}
Hãy thử trực tuyến!
Chỉnh sửa
Thuật toán trong chương trình ban đầu của tôi là tốt, nhưng kích thước tĩnh của kiểu dữ liệu được sử dụng có nghĩa là nó đã phá vỡ khá nhanh khi kích thước vượt quá ngưỡng nhất định.
Tôi đã thay đổi kiểu dữ liệu được sử dụng trong tính toán để tăng giới hạn bộ nhớ của chương trình để phù hợp với điều này (sử dụng BigInteger
cho độ chính xác tùy ý thay vì int
hoặc long
). Tuy nhiên, điều này làm cho nó tranh cãi liệu điều này có được tính là O(1)
phức tạp không gian hay không.
Tôi sẽ để nguyên lời giải thích của mình bên dưới, nhưng tôi muốn nói thêm rằng bây giờ tôi tin rằng không thể đạt được O(1)
sự phức tạp về không gian mà không đưa ra một số giả định.
Bằng chứng
Xác định N
là một số nguyên sao cho 2 <= N
.
Hãy S
là một danh sách đại diện cho một loạt các số nguyên ngẫu nhiên [x{1}, ..., x{N}]
, trong đó x{i}
có các ràng buộc 1 <= x{i} <= N
.
Độ phức tạp thời gian (theo ký hiệu Big-O) cần thiết để lặp qua danh sách này chính xác một lần cho mỗi phần tử là O(n)
Thách thức được đưa ra là tìm giá trị trùng lặp đầu tiên trong danh sách. Cụ thể hơn, chúng tôi đang tìm kiếm giá trị đầu tiên trong S
đó là bản sao của một mục trước đó trong danh sách.
Hãy để p
và q
là vị trí của hai yếu tố trong danh sách như vậy p < q
và x{p} == x{q}
. Thử thách của chúng tôi trở thành việc tìm kiếm nhỏ nhất q
thỏa mãn những điều kiện đó.
Cách tiếp cận rõ ràng cho vấn đề này là lặp qua S và kiểm tra xem chúng tôi x{i}
có tồn tại trong danh sách khác không T
: Nếu x{i}
không tồn tại T
, chúng tôi lưu trữ nó trong T
. Nếu x{i}
không tồn tại T
, nó là giá trị trùng lặp đầu tiên và do đó nhỏ nhất q
, và do đó chúng tôi trả lại nó. Hiệu quả không gian này là O(n)
.
Để đạt được O(1)
độ phức tạp không gian trong khi duy trì O(n)
độ phức tạp thời gian, chúng ta phải lưu trữ thông tin duy nhất về từng đối tượng trong danh sách trong một khoảng không gian hữu hạn. Bởi vì điều này, cách duy nhất mà bất kỳ thuật toán nào có thể thực hiện tạiO(1)
độ phức tạp không gian là nếu: 1. N được đưa ra một giới hạn trên tương ứng với bộ nhớ cần thiết để lưu trữ số lượng giá trị tối đa có thể cho một kiểu dữ liệu hữu hạn cụ thể. 2. Việc gán lại một biến bất biến duy nhất không được tính vào độ phức tạp, chỉ có số lượng biến (một danh sách là nhiều biến). 3. (Dựa trên các câu trả lời khác) Danh sách này (hoặc ít nhất, các phần tử của danh sách) có thể thay đổi và kiểu dữ liệu của danh sách được đặt trước dưới dạng một số nguyên đã ký, cho phép thay đổi được thực hiện cho các phần tử trong danh sách mà không sử dụng bộ nhớ bổ sung.
Cả 1 và 3 đều yêu cầu các giả định và thông số kỹ thuật về kiểu dữ liệu, trong khi 2 yêu cầu chỉ xem xét số lượng biến để tính độ phức tạp không gian, thay vì kích thước của các biến đó. Nếu không có giả định nào được chấp nhận, sẽ không thể đạt được cả O(n)
độ phức tạp thời gian và O(1)
độ phức tạp không gian.
Giải trình
Whoo boy, cái này mất một thời gian dài lúng túng để nghĩ ra một chút sức mạnh não bộ.
Vì vậy, đi kiếm tiền thưởng là khó khăn. Chúng tôi cần cả hai để vận hành trên toàn bộ danh sách chính xác một lần và theo dõi những giá trị nào chúng tôi đã lặp đi lặp lại mà không có độ phức tạp không gian bổ sung.
Thao tác bit giải quyết những vấn đề đó. Chúng tôi khởi tạo O(1)
'lưu trữ' của chúng tôi , một cặp số nguyên, sau đó lặp qua danh sách, HOẶC nhập bit thứ i trong số nguyên đầu tiên của chúng tôi và lưu kết quả đó vào số thứ hai.
Chẳng hạn, nếu chúng ta có 1101
và chúng ta thực hiện thao tác OR 10
, chúng ta sẽ nhận được 1111
. Nếu chúng ta làm khác HOẶC với 10
, chúng ta vẫn có 1101
.
Ergo, một khi chúng tôi thực hiện thao tác OR và kết thúc với cùng một số, chúng tôi đã tìm thấy bản sao của mình. Không có bản sao trong mảng khiến chương trình chạy qua và ném ngoại lệ.