Bạn bước ra một cách nhẹ nhàng, có lẽ bạn không muốn làm việc cho một quỹ phòng hộ mà người đi thuê không hiểu các thuật toán cơ bản :-)
Không có cách nào để xử lý cấu trúc dữ liệu có kích thước tùy ý O(1)
trong trường hợp này, như trong trường hợp này, bạn cần phải truy cập mọi phần tử ít nhất một lần. Điều tốt nhất bạn có thể hy vọng là O(n)
trong trường hợp này, n
độ dài của chuỗi.
Mặc dù, như là một sang một bên, một danh nghĩa O(n)
thuật toán sẽ được O(1)
cho một kích thước đầu vào cố định như vậy, về mặt kỹ thuật, họ có thể đã đúng ở đây. Tuy nhiên, đó thường không phải là cách mọi người sử dụng phân tích phức tạp.
Nó xuất hiện với tôi bạn có thể đã gây ấn tượng với họ theo một số cách.
Đầu tiên, bằng cách thông báo cho họ rằng không thể thực hiện được O(1)
, trừ khi bạn sử dụng lý do "nghi ngờ" nêu trên.
Thứ hai, bằng cách thể hiện các kỹ năng ưu tú của bạn bằng cách cung cấp mã Pythonic như:
inpStr = '123412345123456'
# O(1) array creation.
freq = [0] * 1000
# O(n) string processing.
for val in [int(inpStr[pos:pos+3]) for pos in range(len(inpStr) - 2)]:
freq[val] += 1
# O(1) output of relevant array values.
print ([(num, freq[num]) for num in range(1000) if freq[num] > 1])
Kết quả này:
[(123, 3), (234, 3), (345, 2)]
mặc dù bạn có thể, tất nhiên, sửa đổi định dạng đầu ra thành bất cứ điều gì bạn muốn.
Và cuối cùng, bằng cách nói với họ gần như chắc chắn không có vấn đề gì với một O(n)
giải pháp, vì đoạn mã trên mang lại kết quả cho chuỗi một triệu chữ số trong chưa đầy nửa giây. Nó dường như cũng có quy mô khá tuyến tính, vì một chuỗi 10.000.000 ký tự mất 3,5 giây và một chuỗi 100.000.000 ký tự mất 36 giây.
Và, nếu họ cần tốt hơn thế, có nhiều cách để song song loại công cụ này có thể tăng tốc đáng kể.
Tất nhiên, không phải trong một trình thông dịch Python duy nhất , do GIL, nhưng bạn có thể chia chuỗi thành một cái gì đó giống như ( vv
yêu cầu chồng chéo được chỉ định để cho phép xử lý đúng các khu vực biên):
vv
123412 vv
123451
5123456
Bạn có thể nuôi chúng ra để tách công nhân và kết hợp các kết quả sau đó.
Việc phân tách đầu vào và kết hợp đầu ra có khả năng làm lu mờ bất kỳ sự tiết kiệm nào với các chuỗi nhỏ (và thậm chí có thể là chuỗi triệu chữ số), nhưng đối với các tập dữ liệu lớn hơn nhiều, nó cũng có thể tạo ra sự khác biệt. Tất nhiên, câu thần chú thông thường của tôi về "biện pháp, đừng đoán" áp dụng ở đây.
Câu thần chú này cũng áp dụng cho các khả năng khác , chẳng hạn như bỏ qua Python hoàn toàn và sử dụng một ngôn ngữ khác có thể nhanh hơn.
Ví dụ, mã C sau, chạy trên cùng phần cứng với mã Python trước đó, xử lý một trăm triệu chữ số trong 0,6 giây, gần bằng thời gian khi mã Python xử lý một triệu. Nói cách khác, nhanh hơn nhiều :
#include <stdio.h>
#include <string.h>
int main(void) {
static char inpStr[100000000+1];
static int freq[1000];
// Set up test data.
memset(inpStr, '1', sizeof(inpStr));
inpStr[sizeof(inpStr)-1] = '\0';
// Need at least three digits to do anything useful.
if (strlen(inpStr) <= 2) return 0;
// Get initial feed from first two digits, process others.
int val = (inpStr[0] - '0') * 10 + inpStr[1] - '0';
char *inpPtr = &(inpStr[2]);
while (*inpPtr != '\0') {
// Remove hundreds, add next digit as units, adjust table.
val = (val % 100) * 10 + *inpPtr++ - '0';
freq[val]++;
}
// Output (relevant part of) table.
for (int i = 0; i < 1000; ++i)
if (freq[i] > 1)
printf("%3d -> %d\n", i, freq[i]);
return 0;
}