Câu trả lời ngắn gọn: str
lát, nói chung, sao chép. Điều đó có nghĩa là chức năng của bạn thực hiện một lát cắt cho mỗi hậu tố n
của chuỗi của bạn đang thực hiện công việc O[n2]
. Điều đó nói rằng, bạn có thể tránh các bản sao nếu bạn có thể làm việc với các đối tượng giống như ____ 8 bằng cách sử dụng các ____99 để có được các chế độ xem không sao chép của dữ liệu byte gốc. Xem cách bạn có thể thực hiện việc cắt không sao chép bên dưới để biết cách làm cho nó hoạt động.How you can do zero copy slicing below for
how to make it work.
Câu trả lời dài: [c] Python str
không cắt lát bằng cách tham khảo chế độ xem của một tập hợp con của dữ liệu. Có chính xác ba chế độ hoạt động để cắt str
:
- Hoàn thành lát cắt, ví dụ:
2: Trả về một tham chiếu đến cùng mộtdef do_something_on_all_suffixes[big_string]: # In Py3, may need to encode as latin-1 or the like remaining_suffix = memoryview[big_string] # Rather than explicit loop, just replace view with one shorter view # on each loop while remaining_suffix: # Stop when we've sliced to empty view some_constant_time_operation[remaining_suffix] remaining_suffix = remaining_suffix[1:]
str
[không chỉ là dữ liệu được chia sẻ, cùng một đối tượng thực tế,
4 Vìdef do_something_on_all_suffixes[big_string]: # In Py3, may need to encode as latin-1 or the like remaining_suffix = memoryview[big_string] # Rather than explicit loop, just replace view with one shorter view # on each loop while remaining_suffix: # Stop when we've sliced to empty view some_constant_time_operation[remaining_suffix] remaining_suffix = remaining_suffix[1:]
str
là bất biến nên không có rủi ro khi làm như vậy] - Lát cắt độ dài bằng không và [phụ thuộc thực hiện] chiều dài được lưu trong bộ nhớ cache 1 lát; Chuỗi trống là một singleton [
6] và các chuỗi thứ tự thấp có chiều dài một người được lưu trữ trong bộ nhớ cachletons [trên Cpython 3.5.0, có vẻ như tất cả các ký tự có thể thể hiện trong Latin-1, đó là các thứ tự Unicode trongdef do_something_on_all_suffixes[big_string]: # In Py3, may need to encode as latin-1 or the like remaining_suffix = memoryview[big_string] # Rather than explicit loop, just replace view with one shorter view # on each loop while remaining_suffix: # Stop when we've sliced to empty view some_constant_time_operation[remaining_suffix] remaining_suffix = remaining_suffix[1:]
7, được lưu trữ]def do_something_on_all_suffixes[big_string]: # In Py3, may need to encode as latin-1 or the like remaining_suffix = memoryview[big_string] # Rather than explicit loop, just replace view with one shorter view # on each loop while remaining_suffix: # Stop when we've sliced to empty view some_constant_time_operation[remaining_suffix] remaining_suffix = remaining_suffix[1:]
- Tất cả các lát khác:
str
được cắt lát được sao chép vào thời điểm sáng tạo và sau đó không liên quan đếnstr
ban đầu
Lý do tại sao #3 là quy tắc chung là để tránh các vấn đề với str
lớn được giữ trong bộ nhớ bởi một cái nhìn của một phần nhỏ của nó. Nếu bạn có một tệp 1GB, hãy đọc nó và cắt nó như vậy [vâng, thật lãng phí khi bạn có thể tìm kiếm, đây là để minh họa]:
with open[myfile] as f:
data = f.read[][-1024:]
Sau đó, bạn sẽ có 1 GB dữ liệu được giữ trong bộ nhớ để hỗ trợ cho một chế độ xem cho thấy 1 KB cuối cùng, một chất thải nghiêm trọng. Vì các lát thường nhỏ, nên hầu như luôn luôn nhanh hơn để sao chép trên lát thay vì tạo khung nhìn. Nó cũng có nghĩa là str
có thể đơn giản hơn; Nó cần phải biết kích thước của nó, nhưng nó cũng không cần phải theo dõi một phần bù vào dữ liệu.
Làm thế nào bạn có thể thực hiện việc cắt sao chép không
Có nhiều cách để thực hiện việc cắt dựa trên chế độ xem trong Python và trong Python 2, nó sẽ hoạt động trên str
[vì str
giống như byte trong Python 2, hỗ trợ giao thức đệm]. Với PY2 str
và PY3 bytes
[cũng như nhiều loại dữ liệu khác như
return mystring[::-1]
6, return mystring[::-1]
7, return mystring[::-1]
8 mảng, return mystring[::-1]
9s, v.v.] dữ liệu. Vì vậy, nếu bạn có thể sử dụng [hoặc mã hóa] cho PY2 ________ 5/PY3 bytes
và chức năng của bạn có thể hoạt động với các đối tượng giống như ____ ____ 8, thì bạn có thể làm:are ways to perform view based slicing in Python, and in Python 2, it will work on str
[because str
is bytes-like in Python 2, supporting the buffer protocol]. With Py2 str
and Py3 bytes
[as well as many other data types like return mystring[::-1]
6, return mystring[::-1]
7, return mystring[::-1]
8 arrays, return mystring[::-1]
9s, etc.], you can create a
memoryview
that is a zero copy view of the original object, and can be sliced without copying data. So if you can use [or encode] to Py2 str
/Py3 bytes
, and your function can work with arbitrary bytes
-like objects, then you could do:def do_something_on_all_suffixes[big_string]:
# In Py3, may need to encode as latin-1 or the like
remaining_suffix = memoryview[big_string]
# Rather than explicit loop, just replace view with one shorter view
# on each loop
while remaining_suffix: # Stop when we've sliced to empty view
some_constant_time_operation[remaining_suffix]
remaining_suffix = remaining_suffix[1:]
Các lát của ____99 tạo ra các đối tượng xem mới [chúng chỉ là cực nhẹ với kích thước cố định không liên quan đến lượng dữ liệu chúng xem], không phải bất kỳ dữ liệu nào, vì vậy
return mystring == mystring[::-1]
5 có thể lưu trữ một bản sao nếu cần thay đổi và nó sẽ không được thay đổi Khi chúng ta cắt nó xuống sau. Nếu bạn cần một bản sao thích hợp là PY2 ________ 5/PY3 bytes
, bạn có thể gọi return mystring == mystring[::-1]
8 để lấy bytes
obj thô, hoặc [trong PY3 chỉ xuất hiện], hãy giải mã trực tiếp thành str
sao chép từ bộ đệm, ví dụ: def remove[letter,word]:
new_word=""
for i in word:
if letter!=i:
new_word+=i
return new_word
1. Gần đây tôi đã suy nghĩ về các câu hỏi phỏng vấn mà tôi nhận được khi còn là một sinh viên đại học: những thứ như "đảo ngược một chuỗi" và "Kiểm tra xem một chuỗi là một palindrom".
Things like "reverse a string" and "check if a string is a palindrome".
Tôi đã thực hiện hầu hết trong số này trong C ++ với một vòng lặp và cuộn qua chỉ mục bằng logic.
Khi tôi học Python, tôi nhận ra rằng tôi có thể "đảo ngược một chuỗi" chỉ bằng cách đi:
return mystring[::-1]
Tương tự như vậy với "Kiểm tra xem nó có phải là một palindrom" bằng cách làm:
return mystring == mystring[::-1]
Vấn đề bây giờ là, tôi không biết đó là sự phức tạp như thế nào.
Theo quan điểm của tôi, nó là không đổi, vì vậy O [1]. Nhưng tôi đoán rằng điều đó quá tốt để trở thành sự thật vì việc ghép nối chuỗi đang làm một cái gì đó đằng sau hậu trường.
Bất cứ ai có thể giúp tôi làm rõ?
QN này là từ bài kiểm tra của trường tôi.
Bối cảnh: Trong một trò chơi Hangman, người chơi cố gắng khám phá một từ ẩn bằng cách đoán các chữ cái trong từ. Giả sử tất cả các từ và chữ cái là chữ thường.
Hàm loại bỏ lấy làm đầu vào 2 chuỗi, một chữ cái và một từ và xuất ra từ với tất cả các lần xuất hiện của chữ cái được xóa.
Cung cấp một triển khai lặp lại của chức năng xóa và giải thích ngắn gọn về độ phức tạp về thời gian và không gian của hàm bạn đã viết.
Được đính kèm bên dưới là mã của tôi, giống như giải pháp được cung cấp.
Tuy nhiên, tôi đã bị vấp ngã khi tôi cố gắng giải thích độ phức tạp về thời gian và không gian như O [n] và O [1] tương ứng như câu trả lời được đưa ra là O [n^2] và O [n].
Giải thích được cung cấp bởi giám khảo là:
Độ phức tạp về thời gian: O [n^2] trong đó n là độ dài của chuỗi đầu vào. Điều này là do trong mỗi lần lặp vòng lặp, sự kết hợp chuỗi của new_word sẽ dài hơn cho đến khi nó ở mức tồi tệ nhất, độ dài n.
Độ phức tạp của không gian: O [n], mặc dù không có hoạt động bị trì hoãn hoặc các đối tượng mới được tạo ra mọi lần lặp, chuỗi mới được tạo ra tồi tệ nhất có thể có cùng độ dài với chuỗi ban đầu nếu không có chữ cái nào bị xóa.
Thực hành của tôi là khi tôi giải thích điều gì đó, tôi sẽ có thể vạch ra nó một cách toán học.
Thời gian: Tổng thời gian dành cho mỗi lần lặp hoặc tổng thời gian cho mỗi đệ quy
1] Tôi không hiểu tại sao nối chuỗi đóng góp vào độ phức tạp về thời gian. Đối với các mã đệ quy của nó cắt rõ ràng vì có sự cắt lát chuỗi liên quan [S [0] và S [1:], sự hình thành của S [1:] sẽ lấy O [N-1], O [1] từ S [0] là Không đáng kể] Trong mỗi cuộc gọi đệ quy, tổng thời gian là n+[n-1]+,+1 = o [n^2]. Đối với lời giải thích của lặp đi lặp lại, tôi chỉ cần chấp nhận nó hoặc có một lý thuyết đằng sau lý do tại sao sự kết hợp thêm vào sự phức tạp về thời gian.
Không gian: Tổng không gian được thực hiện cho mỗi đệ quy hoặc tổng không gian được thực hiện cho mỗi lần lặp
2] Ban đầu tôi nghĩ rằng không gian cho đệ quy và lặp lại được tính toán theo cùng một cách. Có đúng không khi chấp nhận rằng để lặp lại, không gian nên được tính là không gian cần thiết cho lần lặp đòi hỏi khắt khe nhất thay vì tổng không gian tích lũy cho tất cả các lần lặp. Yêu cầu nhất sau đó sẽ là khi New_word và Word tương đương.
3] Tôi thực sự chấp nhận thực tế rằng việc lặp lại thường chiếm không gian O [1] và sẽ ném bom mỗi khi tôi có thể. Điều gì thực sự là lý do đằng sau việc coi sự phức tạp không gian của lặp đi lặp lại là O [1] là gì?
Sửa lỗi cho tôi bất cứ lúc nào khi tôi thấy rằng tôi đang ghi nhớ và không hiểu nhiều điều vào thời điểm này.
def remove[letter,word]:
new_word=""
for i in word:
if letter!=i:
new_word+=i
return new_word