O (1) अतिरिक्त स्थान का उपयोग करके दो तार एक दूसरे के क्रमपरिवर्तन हैं या नहीं, इसकी जांच कैसे करें?


13

दो तारों को देखते हुए आप कैसे जांच सकते हैं कि वे O (1) स्पेस का उपयोग करके एक-दूसरे के क्रमपरिवर्तन कर रहे हैं? किसी भी तरह से तारों को संशोधित करने की अनुमति नहीं है।
नोट: दोनों स्ट्रिंग लंबाई और वर्णमाला के आकार के संबंध में O (1) स्थान।


3
तुम क्या सोचते हो? आपने क्या प्रयास किया है, और आप कहां फंस गए हैं? एक निरंतर आकार की वर्णमाला पर तार हैं? क्या आपने उनके हिस्टोग्राम की गणना करने की कोशिश की है?
युवल फिल्मस

@YuvalFilmus यह स्ट्रिंग की लंबाई और वर्णमाला के आकार में O (1) दोनों जगह होना चाहिए
अनाम

यह स्पष्ट रूप से असंभव लगता है। किसी भी एल्गोरिथ्म को एक स्ट्रिंग या एकल वर्ण में कम से कम एक स्थिति को संग्रहीत करने के लिए अतिरिक्त स्थान की आवश्यकता होगी। इनमें से कोई भी चीज O (1) नहीं है।
डेविड श्वार्ट्ज

@DavidSchwartz - कैसे? O (1) का अर्थ है स्थिर, एक नहीं bute। इससे कोई फर्क नहीं पड़ता कि स्ट्रिंग कितनी लंबी है, इसमें स्थिति एक संख्या है।
डावोर

यह मशीन मॉडल पर निर्भर करता है, जाहिर है वर्दी मॉडल में कोई समस्या नहीं है। एक लॉगरिदमिक लागत मॉडल में अनुक्रमणिका O(log n)की लंबाई n के तारों के लिए होती है जो न तो लंबाई के माध्यम से स्थिर होती है और न ही वर्णमाला के आकार के लिए। जब तारों को अस्थायी रूप से संशोधित किया जा सकता है, तो मुझे लगता है कि बढ़ी हुई वर्णमाला के साथ एक समाधान है जो वर्णमाला के आकार में रैखिक है लेकिन एक लॉगरिदमिक मॉडल में स्ट्रिंग लंबाई में स्थिर है।
kap

जवाबों:


7

भोली दृष्टिकोण दोनों तारों के हिस्टोग्राम का निर्माण करेगा और जाँच करेगा कि क्या वे समान हैं। चूंकि हमें ऐसी डेटा संरचना को संग्रहीत करने की अनुमति नहीं है (जिसका आकार वर्णमाला के आकार के लिए रेखीय होगा) जो एक पास में गणना की जा सकती है, हमें एक के बाद एक प्रत्येक संभावित प्रतीक की घटनाओं को गिनने की आवश्यकता है:

function count(letter, string)
    var count := 0
    foreach element in string
        if letter = element
            count++
    return count

function samePermutation(stringA, stringB)
    foreach s in alphabet
        if count(s, stringA) != count(s, stringB)
            return false
    return true

यह निश्चित रूप से मानता है कि मायने रखता है और पुनरावृत्त सूचकांक तार की लंबाई पर निर्भर होने के बजाय निरंतर आकार के पूर्णांक होते हैं।


अनुकूलन के रूप में, आप एक से अधिक सरणी में जा सकते हैं और केवल आपके द्वारा सामना किए जाने वाले अक्षरों के हिस्टोग्राम की गणना कर सकते हैं। इस तरह जटिलता वर्णमाला के आकार से स्वतंत्र हो जाती है।
युवल फिल्मस ५

@YuvalFilmus टिप्पणी पर विस्तार करने के लिए, आपको 1) यह भी जांचना होगा कि स्ट्रिंग की लंबाई समान है या 2) दोनों इनपुट स्ट्रिंग्स पर पुनरावृति। आपको इनमें से एक की आवश्यकता है क्योंकि यह संभव है कि कुछ अक्षर दूसरे में न हों। विकल्प 1 में कम गणनाएँ होनी चाहिए।
BurnsBA

@YuvalFilmus मैं इससे बचना चाहता था क्योंकि इसका मतलब द्विघात समय जटिलता होगा, मैं वर्णमाला औसत स्ट्रिंग आकार से छोटा होने की उम्मीद करूंगा। छोटे तार और एक आदेशित वर्णमाला के लिए, मैं आंतरिक लूप में गिनती के साथ अगले सबसे छोटे वर्तमान प्रतीक की गणना करने पर विचार करूंगा, ताकि कोई वर्णमाला पाश के कुछ पुनरावृत्तियों को छोड़ सके - जिसकी जटिलता के साथ O(n * min(n, |Σ|))। हम्म, अब जब मैं इसके बारे में सोचता हूं, तो यह आपके जवाब से "दोहराने की अनुमति" समाधान की तरह लगता है, है ना?
बरगी

countनहीं है O(1)(यानी यह अतिप्रवाह हो सकता है)
रीइनियरपोस्ट

1
@ अनन्तकोड मैंने कभी नहीं कहा कि countएक int:-) हाँ, यह काम नहीं करेगा, लेकिन जावा में जो वैसे भी नहीं हो सकता है
बर्गी

12

द्वारा सरणियों को निरूपित करें और मान लें कि वे लंबाई ।एनA,Bn

पहले मान लीजिए कि प्रत्येक सरणी में मान अलग-अलग हैं। यहाँ एक एल्गोरिथ्म है जो स्थान का उपयोग करता है:O(1)

  1. दोनों सरणियों के न्यूनतम मूल्यों की गणना करें, और जांचें कि वे समान हैं।

  2. दोनों सरणियों के दूसरे न्यूनतम मूल्यों की गणना करें, और जांचें कि वे समान हैं।

  3. और इसी तरह।

किसी सरणी के न्यूनतम मान की गणना स्पष्ट रूप से स्थान का उपयोग करती है। K वें सबसे छोटे तत्व को देखते हुए , हम ( k + 1 ) st सबसे छोटे तत्व को k वें सबसे छोटे तत्व से बड़ा मान सकते हैं (यहाँ हम इस तथ्य का उपयोग करते हैं कि सभी तत्व अलग हैं)।O(1)k(k+1)k

जब तत्वों को दोहराने की अनुमति दी जाती है, तो हम एल्गोरिथ्म को निम्नानुसार संशोधित करते हैं:

  1. दोनों सरणियों के न्यूनतम मान की गणना करें, गिनें कि प्रत्येक कितनी बार दिखाई देता है, और m A , 1 = m B , 1 को सत्यापित करें और गणना समान हैं।mA,1,mB,1mA,1=mB,1

  2. न्यूनतम मूल्यों की गणना की तुलना में बड़ा मीटर एक , 1 , मी बी , 1 दो सरणियों (क्रमशः) में, और कितनी बार प्रत्येक दिखाई गिनती। सत्यापित करें कि एम , 2 = एम बी , 2 , और यह कि गिनती समान हैं।mA,2,mB,2mA,1,mB,1mA,2=mB,2

  3. और इसी तरह।


1
क्या यह दृष्टिकोण क्योंकि यह O ( 1 ) स्थान में न्यूनतम तत्व को खोजने का एकमात्र तरीका लगता है और सभी तत्वों पर पुनरावृत्ति के लिए सरणी तक केवल-पढ़ने की पहुंच है? O(n2)O(1)
रयान

4
इसके लिए वर्णमाला पर एक आदेश की आवश्यकता होती है, हालांकि एल्गोरिथ्म को बदलने के लिए आसान है कि इसकी आवश्यकता नहीं है। हालाँकि, "डुप्लिकेट्स" मामले में, इसके लिए स्थान की आवश्यकता होती है, O ( 1 ) की नहीं । मतगणना में जगह लेता है। O(lgn)O(1)
डेरेक एल्किंस ने SE

7
गिनती की जरूरत है (लघुगणक) अंतरिक्ष, लेकिन - अंतरिक्ष उपयोग की इस परिभाषा से - तो यह भी सरणी पर पुनरावृत्ति करता है। इस प्रकार, अंतरिक्ष उपयोग के सख्त अर्थ के तहत, इसे निरंतर अंतरिक्ष में करने का कोई तरीका नहीं है।
डैनियल जर्स

4
@DanielJour, यह निर्भर करता है कि आप किस लागत मॉडल का उपयोग कर रहे हैं। एकसमान लागत के तहत, यह निरंतर स्थान में संभव है।
रयान

7
यदि आपको केवल बिट्स की एक निरंतर संख्या की अनुमति है, तो आप केवल निरंतर आकार के अक्षर (यह नियमित भाषाओं के सिद्धांत से अनुसरण करते हैं) को संभाल सकते हैं।
युवल फिल्मस

2

कुछ फंक्शन f (c) को परिभाषित करें जो कुछ कैरेक्टर c को यूनिक प्राइम नंबर (a = 2, b = 3, c = 5, etc) में मैप करता है।

set checksum = 1
set count = 0 <-- this is probably not even necessary, but it's another level of check
for character c in string 1
    checksum = checksum * f(c)
    count = count + 1
for character c in string 2
    checksum = checksum / f(c)
    count = count = 1

permutation = count == 0 and checksum == 1

बस यह घोषित करते हुए कि आप प्राइम नंबर मैपिंग फ़ंक्शन का उपयोग कर सकते हैं, थोड़ा सा हैवी है, और सबसे अधिक संभावना है कि स्पेस रखने में कोई समस्या उत्पन्न होगी ।O(1)


वर्णमाला पर एक बाध्यता के साथ, को ( 1 ) स्थान का उपयोग करना चाहिए , अन्यथा मेरा मानना ​​है कि यह निरंतर स्थान नहीं होगा। इसके अलावा, यदि आपने इसे O ( 1 ) स्थान में गणना की है तो यह वर्तमान परिणामों के आधार पर बेहद अक्षम होगा । फिर भी, primality दृष्टिकोण के लिए +1। f(c)O(1)O(1)
रैन

एक और मुद्दा जिसे मैंने पोस्ट करने के बाद महसूस किया है कि चेकसम बड़े तार के लिए एक विशाल संख्या होने जा रहा है, इस हद तक कि यह स्वयं ओ (1) स्थान की आवश्यकता का उल्लंघन कर सकता है। यह एक स्ट्रिंग पर एक चरित्र द्वारा फ़्लोट्स और म्लिप्लिनिंग का उपयोग करके हल किया जा सकता है, फिर दूसरे पर विभाजित किया जा सकता है, फिर बस चेकसम को पास होना चाहिए 1. स्ट्रिंग्स को वास्तव में एक समस्या होने के लिए फ़्लोटिंग पॉइंट त्रुटि के लिए विशाल होना होगा।
एलेक्स स्टैस

4
O(logn)

4
Θ(n)n

0

आप यह कर सकते हैं O(nlogn)। दो तारों को क्रमबद्ध करें, और उन्हें सूचकांक द्वारा सूचकांक की तुलना करें। यदि वे कहीं भी भिन्न होते हैं, तो वे एक-दूसरे के क्रमपरिवर्तन नहीं करते हैं।

एक O(n)समाधान के लिए, हैशिंग का उपयोग किया जा सकता है। यह हैशिंग फ़ंक्शन काम करेगा, और eकिसी भी पत्र के लिए इसका एएससीआई मूल्य होगा। यदि तार के दो हैश अलग होते हैं, तो वे एक दूसरे के क्रमपरिवर्तन नहीं करते हैं।

लिंक में हैशिंग फ़ंक्शन:

एक संभावित उम्मीदवार यह हो सकता है। एक विषम पूर्णांक R को ठीक करें। प्रत्येक तत्व के लिए e आप कारक (R + 2 * e) को हैश करना चाहते हैं। फिर इन सभी कारकों के उत्पाद की गणना करें। अंत में हैश पाने के लिए उत्पाद को 2 से भाग दें।

कारक 2 इन (आर + 2 ई) गारंटी देता है कि सभी कारक विषम हैं, इसलिए इस बात को टालना कि उत्पाद कभी भी 0. बन जाएगा। अंत में 2 तक विभाजन इसलिए है क्योंकि उत्पाद हमेशा विषम होगा, इसलिए विभाजन सिर्फ एक निरंतर बिट को निकालता है ।

उदाहरण के लिए, मैं R = 1779033703 चुनता हूं। यह एक मनमाना विकल्प है, कुछ प्रयोग करने से पता चलता है कि यदि कोई दिया गया आर अच्छा है या बुरा है। मान लें कि आपके मूल्य [1, 10, 3, 18] हैं। उत्पाद (32-बिट ints का उपयोग करके गणना की गई) है

(R + 2) * (R + 20) * (R + 6) * (R + 36) = 3376724311 इसलिए हैश होगा

3376724311/2 = 1688362155।

R के मान को बदलकर डबल हैशिंग (या अधिक ओवरकिल के लिए) का उपयोग करके उन्हें बहुत अधिक संभावना के साथ क्रमपरिवर्तन के रूप में सफलतापूर्वक पहचाना जाएगा ।


1
जब से आपको उन्हें संशोधित करने की अनुमति नहीं है, आप स्ट्रिंग्स को सॉर्ट नहीं कर सकते। हैशिंग के लिए, यह एक यादृच्छिक एल्गोरिदम है जो गलत उत्तर दे सकता है।
युवल फिल्मस

0

मान लीजिए कि आपके पास s और t नामक दो तार हैं।

आप यह सुनिश्चित करने के लिए कि वे असमान नहीं हैं, उत्तराधिकारियों का उपयोग कर सकते हैं।

  1. s.length == t.length
  2. s == वर्णों का योग t में वर्णों का योग
  3. [में के रूप में ही 2. लेकिन राशि के बजाय xor के साथ]

इसके बाद आप यह साबित करने के लिए आसानी से एक एल्गोरिथ्म चला सकते हैं कि स्ट्रिंग समान हैं।

  1. एक स्ट्रिंग को दूसरे के बराबर होना और तुलना करना (O (n ^ 2))
  2. दोनों को क्रमबद्ध करें और तुलना करें (O (2n log (n))
  3. प्रत्येक तार के लिए जाँच करें यदि दोनों तारों में समान मात्राएँ हैं (O (n ^ 2))

यदि आप अतिरिक्त स्थान का उपयोग करने की अनुमति नहीं हैं, तो बेशक आप उस उपवास को क्रमबद्ध नहीं कर सकते। तो इससे कोई फर्क नहीं पड़ता कि आप कौन सा एल्गोरिथम चुनते हैं - प्रत्येक एल्गोरिथ्म को ओ (एन ^ 2) समय की आवश्यकता होगी जब केवल ओ (1) स्थान होता है और यदि हेयुरिस्टिक यह साबित करने में असमर्थ था कि वे समान नहीं हो सकते हैं।


3
" स्ट्रिंग्स को संशोधित करने की किसी भी तरह से अनुमति नहीं है। "
बर्गी

0

सी-स्टाइल कोड में पूरी दिनचर्या के लिए:

for (int i = 0; i < n; i++) {
   int k = -1;
   next: for (int j = 0; j <= i; j++)
       if (A[j] == A[i]) {
          while (++k < n)
              if (B[k] == A[i])
                  continue next;
          return false; // note at this point j == i
       }
}
return true; 

या बहुत ही मौखिक छद्म कोड में (1-आधारित अनुक्रमण का उपयोग करके)

// our loop invariant is that B contains a permutation of the letters
// in A[1]..A[i-1]
for i=1..n
   if !checkLetters(A, B, i)
      return false
return true

जहां फ़ंक्शन चेकलेटर्स (ए, बी, आई) यह जांचता है कि यदि ए [1] में ए [i] की एम प्रतियां हैं [ए] [ए], तो बी में ए [i] की कम से कम एम प्रतियां हैं:

checkLetters(A,B,i)
    k = 0 // scan index into B
    for j=1..i
      if A[j] = A[i]
         k = findNextValue(B, k+1, A[i])
         if k > n
            return false
    return true

और फ़ंक्शन findNextValue एक सूचकांक से शुरू होने वाले मूल्य के लिए बी में खोज करता है, और उस सूचकांक को वापस करता है जहां यह पाया गया था (या नहीं मिला तो n + 1)।

n2


क्या आप कृपया अपना सी कोड pseudocode में बदल सकते हैं? यह कोई प्रोग्रामिंग साइट नहीं है।
युवल फिल्मस

यह बर्गी के उत्तर के एक और प्रकार की तरह लगता है (कुछ असंगत अंतरों के साथ)।
युवल फिल्मस

O(nm)O(n2)

0

O(n3n

लूप के माध्यम से string1और string2, हर चरित्र की जांच के लिए कितनी बार उस में पाया जा सकता है string1और string2। मेरा किरदार एक स्ट्रिंग में अक्सर दूसरे की तुलना में अधिक है, यह एक क्रमपरिवर्तन नहीं है। यदि सभी वर्णों की आवृत्तियाँ समान हैं, तो तार एक दूसरे के क्रमपरिवर्तन हैं।

इस सटीक बनाने के लिए यहां अजगर का एक टुकड़ा है

s1="abcaba"
s2="aadbba"

def check_if_permutations(string1, string2):
  for string in [string1, string2]:
    # string references string1 
    #  string2, it is not a copy
    for char in string:
      count1=0
      for char1 in string1:
        if  char==char1:
          count1+=1
      count2=0
      for char2 in string2:
        if  char==char2:
          count2+=1
      if count1!=count2:
        print('unbalanced character',char)
        return()
  print ("permutations")
  return()

check_if_permutations(s1,s2)

stringstring1string2charchar1char2O(logn)count1count2string[string1, string2]

बेशक आपको गिनती चर की भी आवश्यकता नहीं है, लेकिन पॉइंटर्स का उपयोग कर सकते हैं।

s1="abcaba"
s2="aadbba"

def check_if_permutations(string1, string2):
  for string in [string1, string2]:
    # string references one of string1 
    # or string2, it is not a copy
    for char in string:
      # p1 and p2 should be views as pointers
      p1=0
      p2=0
      while (p1<len(string1)) and (p2<len(string2)):
        # p1>=len(string1): p1 points to beyond end of string
        while (p1<len(string1)) and (string1[p1]!=char) :
          p1+=1
        while(p2<len(string2)) and (string2[p2]!=char):
          p2+=1
        if (p1<len(string1)) != (p2<len(string2)):
          print('unbalanced character',char)
          return()
        p1+=1
        p2+=1
  print ("permutations")
  return()

check_if_permutations(s1,s2)

O(log(n))

n


यह नीचे दिए गए बर्गी के समाधान के समान है।
युवल फिल्मस

@YuvalFilmus नहीं, यह पूरे वर्णमाला पर पुनरावृति नहीं करता है और इसलिए इसका रनटाइम वर्णमाला के आकार पर निर्भर नहीं करता है। यह केवल उन दो तारों का उपयोग करता है जिन्हें परीक्षण किया जाना चाहिए। इसके अलावा दूसरा कार्यक्रम गिनती से बचा जाता है।
चमत्कार 173

@YuvalFilmus अब मैं देख रहा हूं, कि आपके और अन्य टिप्पणियां मेरे कार्यक्रम में उपयोग किए जाने के तरीके की दिशा में इंगित करते हैं।
चमत्कार 173
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.