क्या पुनरावृति स्ट्रिंग एपेंड की समय-जटिलता वास्तव में हे (n ^ 2), या O (n) है?


89

मैं सीटीआई से बाहर एक समस्या पर काम कर रहा हूं।

अध्याय 1 की तीसरी समस्या आपने एक स्ट्रिंग ली है जैसे कि

'Mr John Smith '

और आपको मध्यस्थ स्थानों को बदलने के लिए कहता है %20:

'Mr%20John%20Smith'

लेखक पायथन में इस समाधान की पेशकश करता है, इसे O (n) कहते हैं:

def urlify(string, length):
    '''function replaces single spaces with %20 and removes trailing spaces'''
    counter = 0
    output = ''
    for char in string:
        counter += 1
        if counter > length:
            return output
        elif char == ' ':
            output = output + '%20'
        elif char != ' ':
            output = output + char
    return output

मेरा प्रश्न:

मैं समझता हूं कि यह वास्तविक स्ट्रिंग के माध्यम से बाएं से दाएं स्कैनिंग के संदर्भ में ओ (एन) है। लेकिन पायथन अपरिवर्तनीय में तार नहीं हैं? यदि मेरे पास एक स्ट्रिंग है और मैं +ऑपरेटर के साथ एक और स्ट्रिंग जोड़ देता हूं , तो क्या यह आवश्यक स्थान आवंटित नहीं करता है, मूल पर प्रतिलिपि बनाता है, और फिर अपंग स्ट्रिंग पर कॉपी करता है?

अगर मेरे पास nप्रत्येक लंबाई 1 के तार का संग्रह है , तो यह है:

1 + 2 + 3 + 4 + 5 + ... + n = n(n+1)/2

या O (n ^ 2) समय , हाँ? या क्या मैं गलत हूँ कि पायथन को किस तरह से जोड़ा जाता है?

वैकल्पिक रूप से, अगर आप मुझे मछली मारने का तरीका सिखाने के लिए तैयार हैं: तो मैं इसे अपने लिए कैसे खोजूंगा? मैं Google के आधिकारिक स्रोत के अपने प्रयासों में असफल रहा हूँ। मैंने https://wiki.python.org/moin/TimeComplexity पाया, लेकिन इसमें स्ट्रिंग्स पर कुछ भी नहीं है।


17
किसी लेखक बता के बारे में जाना चाहिएurllib.urlencode
विम

11
@wim का अर्थ है सरणियों और तारों के बारे में एक अभ्यास समस्या
user5622964

3
पुस्तक का उद्देश्य साक्षात्कार प्रश्नों को पढ़ाना है, जो आमतौर पर आपको साक्षात्कारकर्ता की विचार प्रक्रिया को देखने के लिए पहिया का फिर से आविष्कार करने के लिए कहते हैं।
जेम्स विर्ज़बा

1
चूंकि यह अजगर है, मैं एक कर रही है लगता है कि rtrimऔर replaceअधिक पसंद किया और की बॉलपार्क में किया जाएगा O(n)। तार पर नकल कम से कम कुशल तरीका लगता है।
OneCricketeer

2
@ रनर क्या आप बता सकते हैं कि एक कॉपी लगातार समय कैसे ले सकती है?
जेम्स विर्ज़बा

जवाबों:


83

सीपीथॉन में, पायथन के मानक कार्यान्वयन, एक कार्यान्वयन विवरण है जो इसे आमतौर पर O (n) बनाता है, कोड++= में लागू किया गया है जो दो स्ट्रिंग ऑपरेंड के लिए या उसके साथ बाईटकोड मूल्यांकन लूप कॉल करता है । यदि पायथन को पता चलता है कि बाएं तर्क में कोई अन्य संदर्भ नहीं है, तो यह reallocस्ट्रिंग को जगह में बदलकर प्रतिलिपि से बचने का प्रयास करता है। यह ऐसा कुछ नहीं है जिस पर आपको कभी भरोसा करना चाहिए, क्योंकि यह एक कार्यान्वयन विवरण है और क्योंकि यदि reallocस्ट्रिंग को अक्सर स्थानांतरित करने की आवश्यकता होती है, तो प्रदर्शन ओ (एन ^ 2) के लिए वैसे भी खराब हो जाता है।

अजीब कार्यान्वयन विस्तार के बिना, एल्गोरिथ्म ओ (एन ^ 2) है जिसमें शामिल नकल की द्विघात राशि है। इस तरह कोड केवल सी + + और यहां तक ​​कि सी ++ में आप का उपयोग करना चाहते हैं के साथ एक भाषा में समझ में आता है +=


2
मैं आपके द्वारा लिंक किए गए कोड को देख रहा हूं ... ऐसा लग रहा है कि उस कोड का एक बड़ा हिस्सा स्ट्रिंगर्स के संदर्भ / संदर्भ को हटा रहा है, जो कि सही है? और फिर अंत की ओर यह _PyString_Resize(&v, new_len)समवर्ती स्ट्रिंग के लिए मेमोरी आवंटित करने के लिए प्रदर्शन करता है, और फिर memcpy(PyString_AS_STRING(v) + v_len, PyString_AS_STRING(w), w_len);कॉपी करता है। यदि इन-प्लेस आकार बदलने में विफल रहता है, तो यह करता है PyString_Concat(&v, w);(मैं इसका मतलब है कि मूल स्ट्रिंग पते के अंत में सन्निहित स्मृति मुक्त नहीं है)। यह स्पीडअप कैसे दिखाता है?
user5622964

मैं अपनी पिछली टिप्पणी में अंतरिक्ष से बाहर भाग गया, लेकिन मेरा सवाल यह है कि क्या मैं उस कोड को सही ढंग से समझ रहा हूं या नहीं और उन टुकड़ों के मेमोरी उपयोग / रनटाइम की व्याख्या कैसे करूं।
user5622964

1
@ user5622964: वूप्स, अजीब कार्यान्वयन विस्तार को गलत बताया। कोई कुशल आकार परिवर्तन नीति नहीं है; यह सिर्फ कॉल करता है reallocऔर अच्छे के लिए उम्मीद करता है।
user2357112

कैसे memcpy(PyString_AS_STRING(v) + v_len, PyString_AS_STRING(w), w_len);काम करता है ? Cplusplus.com/reference/cstring/memcpy के अनुसार इसकी परिभाषा void * memcpy ( void * destination, const void * source, size_t num );और विवरण है: "Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination."इस मामले में संख्या, अपग्रेडिंग स्ट्रिंग का आकार है, और स्रोत दूसरी स्ट्रिंग का पता है, मुझे लगता है? लेकिन फिर गंतव्य (पहला स्ट्रिंग) + लेन (पहला स्ट्रिंग) क्यों है? डबल मेमोरी?
user5622964

7
@ user5622964: यह सूचक अंकगणित है। यदि आप CPYthon स्रोत कोड को अजीब कार्यान्वयन विवरणों को समझना चाहते हैं, तो आपको सी। जानना होगा। सुपर-कंडेंस्ड संस्करण वह PyString_AS_STRING(v)है जो पहले स्ट्रिंग के डेटा का पता है, और जोड़ने v_lenसे आपको स्ट्रिंग के ठीक बाद का पता मिल जाता है डेटा समाप्त होता है।
user2357112

40

लेखक यहाँ होने वाले अनुकूलन पर निर्भर करता है, लेकिन स्पष्ट रूप से भरोसेमंद नहीं है। strA = strB + strCआम तौर पर O(n), फ़ंक्शन बना रहा है O(n^2)। हालांकि, यह सुनिश्चित करना बहुत आसान है कि यह पूरी प्रक्रिया है O(n), एक सरणी का उपयोग करें:

output = []
    # ... loop thing
    output.append('%20')
    # ...
    output.append(char)
# ...
return ''.join(output)

संक्षेप में, appendऑपरेशन को बढ़ाया जाता है O(1) , (हालांकि आप इसे O(1)सही आकार में सरणी को पूर्व-आवंटित करके मजबूत बना सकते हैं ), जिससे लूप बन जाता है O(n)

और फिर joinयह भी है O(n), लेकिन यह ठीक है क्योंकि यह लूप के बाहर है।


यह उत्तर अच्छा है क्योंकि यह बताता है कि कैसे तारों को समतल करना है।
user877329

रनटाइम की गणना के संदर्भ में सटीक उत्तर।
इंटेर हैदर

25

मुझे पायथन स्पीड पर पाठ का यह टुकड़ा मिला > सबसे अच्छा एल्गोरिदम और सबसे तेज़ टूल का उपयोग करें :

स्ट्रिंग संघनन सबसे अच्छा है ''.join(seq)जिसके साथ एक O(n)प्रक्रिया है। इसके विपरीत, '+'या '+='ऑपरेटरों के उपयोग से एक O(n^2)प्रक्रिया हो सकती है क्योंकि प्रत्येक मध्यवर्ती चरण के लिए नए तार बनाए जा सकते हैं। CPython 2.4 दुभाषिया इस मुद्दे को कुछ हद तक कम करता है; हालाँकि, ''.join(seq)सबसे अच्छा अभ्यास है


3

भविष्य के आगंतुकों के लिए: चूँकि यह CTCI प्रश्न है, इसलिए urllib पैकेज सीखने के लिए किसी भी संदर्भ की आवश्यकता नहीं है, विशेष रूप से OP और पुस्तक के अनुसार, यह प्रश्न Arrays और Strings के बारे में है।

यहाँ एक और पूर्ण समाधान है, जो @ njzk2 के छद्म से प्रेरित है:

text = 'Mr John Smith'#13 
special_str = '%20'
def URLify(text, text_len, special_str):
    url = [] 
    for i in range(text_len): # O(n)
        if text[i] == ' ': # n-s
            url.append(special_str) # append() is O(1)
        else:
            url.append(text[i]) # O(1)

    print(url)
    return ''.join(url) #O(n)


print(URLify(text, 13, '%20'))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.