एक इनपुट में चक्रीय शब्दों की संख्या गिनें


9

चक्रीय शब्द

समस्या का विवरण

हम चक्रीय शब्द को एक चक्र में लिखे गए शब्द के रूप में सोच सकते हैं। चक्रीय शब्द का प्रतिनिधित्व करने के लिए, हम एक अनियंत्रित प्रारंभिक स्थिति चुनते हैं और वर्णों को दक्षिणावर्त क्रम में पढ़ते हैं। तो, "चित्र" और "ट्यूरिक" एक ही चक्रीय शब्द के लिए अभ्यावेदन हैं।

आपको एक स्ट्रिंग [] शब्द दिए गए हैं, जिनमें से प्रत्येक तत्व एक चक्रीय शब्द का प्रतिनिधित्व है। प्रतिनिधित्व किए जाने वाले विभिन्न चक्रीय शब्दों की संख्या लौटाएँ।

सबसे तेज़ जीत (बिग ओ, जहां n = स्ट्रिंग में वर्णों की संख्या)


3
यदि आप अपने कोड की आलोचना कर रहे हैं, तो जाने का स्थान कोडरेव्यू.स्टैकएक्सचेंज.कॉम है।
पीटर टेलर

ठंडा। मैं चुनौती पर जोर देने के लिए संपादन करूंगा और आलोचना के भाग को कोड समीक्षा में स्थानांतरित करूंगा। धन्यवाद पीटर।
अंडोंगेल्स

1
विजयी मापदंड क्या है? सबसे छोटा कोड (कोड गोल्फ) या कुछ और? क्या इनपुट और आउटपुट के रूप में कोई सीमाएं हैं? क्या हमें एक फ़ंक्शन या पूरा कार्यक्रम लिखने की आवश्यकता है? क्या यह जावा में होना चाहिए?
१६:१३

1
@eggonlegs आपने बड़े-O निर्दिष्ट किए - लेकिन किस पैरामीटर के संबंध में? सरणी में स्ट्रिंग्स की संख्या? क्या स्ट्रिंग तुलना ओ (1) है? या तार में संख्याओं की संख्या या वर्णों की कुल संख्या? या फिर कुछ और?
हावर्ड १

1
@ यार, निश्चित रूप से यह 4 है?
पीटर टेलर

जवाबों:


4

अजगर

यहाँ मेरा समाधान है। मुझे लगता है कि यह अभी भी ओ (एन 2 ) हो सकता है , लेकिन मुझे लगता है कि औसत मामला इससे बेहतर है।

मूल रूप से यह प्रत्येक स्ट्रिंग को सामान्य करके काम करता है ताकि किसी भी घुमाव का एक ही रूप हो। उदाहरण के लिए:

'amazing' -> 'mazinga'
'mazinga' -> 'mazinga'
'azingam' -> 'mazinga'
'zingama' -> 'mazinga'
'ingamaz' -> 'mazinga'
'ngamazi' -> 'mazinga'
'gamazin' -> 'mazinga'

सामान्यकरण न्यूनतम वर्ण (चार कोड द्वारा) की तलाश में किया जाता है, और स्ट्रिंग को घुमाया जाता है ताकि चरित्र अंतिम स्थिति में हो। यदि वह चरित्र एक से अधिक बार होता है, तो प्रत्येक घटना के बाद के पात्रों का उपयोग किया जाता है। यह प्रत्येक चक्रीय शब्द को एक विहित प्रतिनिधित्व देता है, जिसका उपयोग मानचित्र में एक कुंजी के रूप में किया जा सकता है।

सामान्यीकरण सबसे खराब स्थिति में n 2 है (जहां स्ट्रिंग में प्रत्येक वर्ण समान है, उदाहरण के लिए aaaaaa), लेकिन अधिकांश समय केवल कुछ घटनाएँ होने वाला है, और चलने का समय करीब हो जाएगा n

मेरे लैपटॉप पर (दोहरे कोर इंटेल एटम @ 1.66GHz और 1GB RAM), इस पर चलने /usr/share/dict/words(9.5 वर्णों की औसत लंबाई के साथ 234,937 शब्द) लगभग 7.6 सेकंड लगते हैं।

#!/usr/bin/python

import sys

def normalize(string):
   # the minimum character in the string
   c = min(string) # O(n) operation
   indices = [] # here we will store all the indices where c occurs
   i = -1       # initialize the search index
   while True: # finding all indexes where c occurs is again O(n)
      i = string.find(c, i+1)
      if i == -1:
         break
      else:
         indices.append(i)
   if len(indices) == 1: # if it only occurs once, then we're done
      i = indices[0]
      return string[i:] + string[:i]
   else:
      i = map(lambda x:(x,x), indices)
      for _ in range(len(string)):                       # go over the whole string O(n)
         i = map(lambda x:((x[0]+1)%len(string), x[1]), i)  # increment the indexes that walk along  O(m)
         c = min(map(lambda x: string[x[0]], i))    # get min character from current indexes         O(m)
         i = filter(lambda x: string[x[0]] == c, i) # keep only the indexes that have that character O(m)
         # if there's only one index left after filtering, we're done
         if len(i) == 1:
            break
      # either there are multiple identical runs, or
      # we found the unique best run, in either case, we start the string from that
      # index
      i = i[0][0]
      return string[i:] + string[:i]

def main(filename):
   cyclic_words = set()
   with open(filename) as words:
      for word in words.readlines():
         cyclic_words.add(normalize(word[:-1])) # normalize without the trailing newline
   print len(cyclic_words)

if __name__ == '__main__':
   if len(sys.argv) > 1:
      main(sys.argv[1])
   else:
      main("/dev/stdin")

3

अजगर (3) फिर से

मेरे द्वारा उपयोग की जाने वाली विधि स्ट्रिंग में प्रत्येक वर्ण पर शुरू होने वाले प्रत्येक शब्द के एक रोलिंग हैश की गणना करना था; चूँकि यह एक रोलिंग हैश है, इसलिए इसे सभी n हैश की गणना करने के लिए O (n) (जहाँ n शब्द की लंबाई है) समय लगता है। स्ट्रिंग को आधार -1114112 नंबर के रूप में माना जाता है, जो हैश को अद्वितीय बनाता है। (यह हास्केल समाधान के समान है, लेकिन अधिक कुशल है क्योंकि यह केवल दो बार स्ट्रिंग से गुजरता है।)

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

कमांड-लाइन तर्क एक फ़ाइल का नाम होना चाहिए जिसमें प्रति पंक्ति एक शब्द होता है (जैसे /usr/share/dict/words)।

import sys

def rollinghashes(string):
    base = 1114112
    curhash = 0
    for c in string:
        curhash = curhash * base + ord(c)
    yield curhash
    top = base ** len(string)
    for i in range(len(string) - 1):
        curhash = curhash * base % top + ord(string[i])
        yield curhash

def cycles(words, keepuniques=False):
    hashes = set()
    uniques = set()
    n = 0
    for word in words:
        h = min(rollinghashes(word))
        if h in hashes:
            continue
        else:
            n += 1
            if keepuniques:
                uniques.add(word)
            hashes.add(h)
    return n, uniques

if __name__ == "__main__":
    with open(sys.argv[1]) as words_file:
        print(cycles(line.strip() for line in words_file)[0])

1

हास्केल

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

यदि n सूची में शब्दों की संख्या है और m किसी शब्द की लंबाई है तो सभी शब्दों के लिए 'चक्रीय समूह संख्या' की गणना करना O(n*m), छांटना O(n log n)और समूह बनाना है O(n)

import Data.List
import Data.Char
import Data.Ord
import Data.Function

groupUnsortedOn f = groupBy ((==) `on` f) . sortBy(compare `on` f)
allCycles w = init $ zipWith (++) (tails w)(inits w)
wordval = foldl (\a b -> a*256 + (fromIntegral $ ord b)) 0
uniqcycle = minimumBy (comparing wordval) . allCycles
cyclicGroupCount = length . groupUnsortedOn uniqcycle

1

मेथेमेटिका

फिर से शुरू करने का फैसला किया, अब जब मैं खेल के नियमों को समझता हूं (मुझे लगता है)।

लंबाई के अनूठे यादृच्छिक रूप से बनाए गए "शब्दों" (केवल निचला मामला) का एक 10000 शब्द शब्दकोश 3. इसी तरह के अन्य शब्दों में लंबाई 4, 5, 6, 7 और 8 के तार शामिल थे।

ClearAll[dictionary]      
dictionary[chars_,nWords_]:=DeleteDuplicates[Table[FromCharacterCode@RandomInteger[{97,122},
chars],{nWords}]];
n=16000;
d3=Take[dictionary[3,n],10^4];
d4=Take[dictionary[4,n],10^4];
d5=Take[dictionary[5,n],10^4];
d6=Take[dictionary[6,n],10^4];
d7=Take[dictionary[7,n],10^4];
d8=Take[dictionary[8,n],10^4];

gजाँच करने के लिए शब्दकोश का वर्तमान संस्करण लेता है। शीर्ष शब्द चक्रीय वेरिएंट (यदि कोई मौजूद है) के साथ जुड़ा हुआ है। शब्द और उसके मिलान आउटपुट सूची में out, संसाधित शब्दों के लिए जोड़े जाते हैं । आउटपुट शब्द शब्दकोश से हटा दिए जाते हैं।

g[{wds_,out_}] := 
   If[wds=={},{wds,out},
   Module[{s=wds[[1]],t,c},
   t=Table[StringRotateLeft[s, k], {k, StringLength[s]}];
   c=Intersection[wds,t];
   {Complement[wds,t],Append[out,c]}]]

f सभी शब्द शब्दकोश के माध्यम से चलता है।

f[dict_]:=FixedPoint[g,{dict,{}}][[2]]

उदाहरण 1 : वास्तविक शब्द

r = f[{"teaks", "words", "spot", "pots", "sword", "steak", "hand"}]
Length[r]

{{"स्टेक", "टीक्स"}, {"हैंड"}, {"पॉट्स", "स्पॉट"}, {"तलवार", "शब्द"}}
4


उदाहरण 2 : कृत्रिम शब्द। लंबाई के तारों का शब्दकोश 3. पहला, समय। फिर चक्र शब्दों की संख्या।

f[d3]//AbsoluteTiming
Length[%[[2]]]

d3

5402


शब्द की लंबाई के एक समारोह के रूप में समय । प्रत्येक शब्दकोष में 10000 शब्द।

समय

मैं विशेष रूप से ओ के संदर्भ में निष्कर्षों की व्याख्या करने का तरीका नहीं जानता। सरल शब्दों में, तीन वर्ण शब्दकोष से चार वर्ण शब्दकोश में समय लगभग दोगुना हो जाता है। समय 8 में से 4 अक्षरों के माध्यम से लगभग लापरवाही से बढ़ता है।


क्या आप संभवतः आपके द्वारा उपयोग किए गए शब्दकोश का लिंक पोस्ट कर सकते हैं ताकि मैं आपके खिलाफ तुलना कर सकूं?
अंडोलेग्स

Dictionary.txt के लिए निम्न लिंक काम करना चाहिए: बिटशेयर.com / files / oy62qgro / dEDIA.txt.html (क्षमा करें, जिस मिनट को शुरू करने के लिए आपको इंतजार करना होगा।) BTW, फ़ाइल में 3char, 4char है। ... 8char सभी को मिलाकर, प्रत्येक में 10000 शब्द। आप उन्हें अलग करना चाहेंगे।
डेविड जे

बहुत बढ़िया। बहुत बहुत धन्यवाद :)
eggonlegs

1

यह O (n) में द्विघात समय से बचने के लिए किया जा सकता है। बेस स्ट्रिंग को दो बार फुल सर्कल बनाने का विचार है। इसलिए हम "आश्चर्यजनक" के समान सभी चक्रीय तारों की जांच करने के लिए पूर्ण सर्कल स्ट्रिंग के रूप में "अमेज़ॅमाज़िन" का निर्माण करते हैं।

नीचे जावा समाधान है:

public static void main(String[] args){
    //args[0] is the base string and following strings are assumed to be
    //cyclic strings to check 
    int arrLen = args.length;
    int cyclicWordCount = 0;
    if(arrLen<1){
        System.out.println("Invalid usage. Supply argument strings...");
        return;
    }else if(arrLen==1){
        System.out.println("Cyclic word count=0");
        return;         
    }//if

    String baseString = args[0];
    StringBuilder sb = new StringBuilder();
    // Traverse base string twice appending characters
    // Eg: construct 'amazingamazin' from 'amazing'
    for(int i=0;i<2*baseString.length()-1;i++)
        sb.append(args[0].charAt(i%baseString.length()));

    // All cyclic strings are now in the 'full circle' string
    String fullCircle = sb.toString();
    System.out.println("Constructed string= "+fullCircle);

    for(int i=1;i<arrLen;i++)
    //Do a length check in addition to contains
     if(baseString.length()==args[i].length()&&fullCircle.contains(args[i])){
        System.out.println("Found cyclic word: "+args[i]);
        cyclicWordCount++;
    }

    System.out.println("Cyclic word count= "+cyclicWordCount);
}//main

0

मुझे नहीं पता कि यह बहुत कुशल है, लेकिन यह मेरी पहली दरार है।

private static int countCyclicWords(String[] input) {
    HashSet<String> hashSet = new HashSet<String>();
    String permutation;
    int count = 0;

    for (String s : input) {
        if (hashSet.contains(s)) {
            continue;
        } else {
            count++;
            for (int i = 0; i < s.length(); i++) {
                permutation = s.substring(1) + s.substring(0, 1);
                s = permutation;
                hashSet.add(s);
            }
        }
    }

    return count;
}

0

पर्ल

मुझे यकीन नहीं है कि मैं समस्या को समझता हूं, लेकिन यह कम से कम टिप्पणियों में पोस्ट किए गए @dude से मेल खाता है। कृपया मेरे निश्चित गलत विश्लेषण को सही करें।

स्ट्रिंग सूची के दिए गए एन शब्दों में प्रत्येक शब्द डब्ल्यू के लिए, आपको सबसे खराब स्थिति में डब्ल्यू के सभी पात्रों के माध्यम से कदम रखना होगा। मुझे लगता है कि हैश संचालन निरंतर समय में किया जाता है।

use strict;
use warnings;

my @words = ( "teaks", "words", "spot", "pots", "sword", "steak", "hand" );

sub count
{
  my %h = ();

  foreach my $w (@_)
  {
    my $n = length($w);

    # concatenate the word with itself. then all substrings the
    # same length as word are rotations of word.
    my $s = $w . $w;

    # examine each rotation of word. add word to the hash if
    # no rotation already exists in the hash
    $h{$w} = undef unless
      grep { exists $h{substr $s, $_, $n} } 0 .. $n - 1;
  }

  return keys %h;
}

print scalar count(@words), $/;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.