2009-05-19 7 views
12

जैसे यदि इनपुट स्ट्रिंग HelloWorld मैं उत्पादन की तरह बनना चाहते हैं:एल्गोरिदम सभी शब्दों की एक सूची प्राप्त करने के लिए जो सभी सबस्ट्रिंग्स (स्क्रैबल) के एनाग्राम हैं?

do 
he 
we 
low 
hell 
hold 
roll 
well 
word 
hello 
lower 
world 
... 

सब सबसे लंबा शब्द HelloWorld की सबस्ट्रिंग का विपर्यय शब्द है कि जिस तरह से। उदाहरण के लिए स्क्रैबल में पसंद है। इनपुट स्ट्रिंग किसी भी लंबाई हो सकती है, लेकिन शायद ही कभी 16 से अधिक वर्ण।

मैंने एक खोज की है और एक त्रिभुज की तरह संरचनाओं के साथ आ गया है, लेकिन मुझे अभी भी यह सुनिश्चित नहीं है कि वास्तव में यह कैसे किया जाए।

+0

कैसे "do" आ उपरोक्त मामले में कोई मान्य स्ट्रिंग है? यह किसी भी substring ryt का एक आरेख नहीं है? – nitish712

+0

@ nitish712 "do" मान्य है क्योंकि अक्षरों 'डी' और 'ओ' इनपुट स्ट्रिंग में हैं। – PowerApp101

उत्तर

14

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

आपका परीक्षक कार्य रिकर्सिव होगा। यह शून्य अक्षरों से शुरू होता है, वैध प्रविष्टियों के पेड़ से मिलता है जो कि "" एक शब्द नहीं है लेकिन इसमें बच्चे हैं, इसलिए आप अपने परीक्षक को अपने प्रारंभिक शब्द (बिना अक्षरों के) के साथ दोबारा कॉल करें, जिसमें प्रत्येक उपलब्ध शेष पत्र के साथ जोड़ा गया है इनपुट स्ट्रिंग (जो उस समय उन सभी पर है)। यदि वैध नोट नोट करें, तो पेड़ में प्रत्येक एक-अक्षर प्रविष्टि की जांच करें; यदि बच्चे, शेष उपलब्ध अक्षरों में से प्रत्येक को संलग्न करने वाले परीक्षक फ़ंक्शन को फिर से कॉल करें, और इसी तरह।

तो उदाहरण के लिए, यदि आपकी इनपुट स्ट्रिंग "helloworld" है, तो आप पहले रिकॉर्डेबल परीक्षक फ़ंक्शन को "" के साथ कॉल कर सकते हैं, शेष उपलब्ध अक्षर "helloworld" को दूसरे पैरामीटर के रूप में पास कर सकते हैं। फंक्शन देखता है कि "" एक शब्द नहीं है, लेकिन बच्चा "एच" मौजूद है। तो यह खुद को "एच", और "अलौकिक" के साथ बुलाता है। कार्य देखता है कि "एच" एक शब्द नहीं है, लेकिन बच्चा "ई" मौजूद है। तो यह खुद को "वह" और "lloworld" के साथ बुलाता है। फंक्शन देखता है कि "ई" चिह्नित है, इसलिए "वह" एक शब्द है, ध्यान दें। इसके अलावा, बच्चा "एल" मौजूद है, इसलिए अगली कॉल "लोअर" के साथ "हेल" है। इसके बाद इसे "नरक" मिलेगा, फिर "हैलो", फिर उसे वापस "पीछे हटना होगा" और शायद अगले स्ट्रिंग पर फिर से बैक करने से पहले और फिर "ई" शब्दों के साथ शुरू करने से पहले "खोखला" ढूंढना होगा।

+0

मुझे यह स्पष्टीकरण पसंद है। मैं (लगभग) इसके चारों ओर अपना सिर प्राप्त कर सकता हूं। मुझे लगता है कि कलम और कागज विश्लेषण करने की जरूरत है। – PowerApp101

+0

ऐसा लगता है कि यह नॉर्मन रैमसे के डीएडब्ल्यूजी (अन्य पोस्ट) के बहुत करीब है; पता होना चाहिए कि इसके लिए औपचारिक परिभाषा थी। –

+0

नहीं ... मैंने इस बारे में सोचा है और फैसला किया है कि मैं परीक्षक समारोह को समझ नहीं पा रहा हूं। मैं समझता हूं कि पेड़ कैसे बनाया जाए। यह "हैलो" से "खोखले" तक कैसे मिलता है? रिकर्सन कभी मेरा मजबूत बिंदु नहीं था! – PowerApp101

2

आप जो चाहते हैं वह power set का कार्यान्वयन है।

इसके अलावा एरिक Lipparts ब्लॉग को देखो, वह भी ब्लॉग के बारे में this very thing थोड़ी देर वापस

संपादित करें:

यहाँ एक कार्यान्वयन मैं एक दिया स्ट्रिंग से Powerset हो रही के बारे में लिखा है ...

private IEnumerable<string> GetPowerSet(string letters) 
{ 
    char[] letterArray = letters.ToCharArray(); 
    for (int i = 0; i < Math.Pow(2.0, letterArray.Length); i++) 
    { 
    StringBuilder sb = new StringBuilder(); 
    for (int j = 0; j < letterArray.Length; j++) 
    { 
     int pos = Convert.ToInt32(Math.Pow(2.0, j)); 
     if ((pos & i) == pos) 
     { 
     sb.Append(letterArray[j]); 
     } 
    } 
    yield return new string(sb.ToString().ToCharArray().OrderBy(c => c).ToArray()); 
    } 
} 

यह फ़ंक्शन मुझे तारों की शक्तियां देता है जो स्ट्रिंग में पारित होते हैं, फिर मैं इन्हें एनाग्राम के शब्दकोश में चाबियों के रूप में उपयोग कर सकता हूं ...

Dictionary<string,IEnumerable<string>> 

मैं बहुत तरह विपर्यय के अपने शब्दकोश बनाया ... (वहाँ शायद और अधिक कुशल तरीके हैं, लेकिन इस सरल और बहुत जल्दी पर्याप्त स्क्रैबल टूर्नामेंट शब्द सूची के साथ था)

wordlist = (from s in fileText.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) 
       let k = new string(s.ToCharArray().OrderBy(c => c).ToArray()) 
       group s by k).ToDictionary(o => o.Key, sl => sl.Select(a => a)); 
0

Tim J, Eric Lippert की ब्लॉग पोस्ट्स जहां पहली बात मेरे दिमाग में आती है। मैं यह जोड़ना चाहता था कि उन्होंने अपने पहले प्रयास के प्रदर्शन में सुधार के तरीकों के बारे में एक फॉलो-अप लिखा था।

2

एक साधारण दिमाग दृष्टिकोण सभी "सबस्ट्रिंग" और उनमें से प्रत्येक के लिए, उत्पन्न करने के लिए, जाँच करें कि क्या यह स्वीकार्य शब्द के सेट का एक तत्व है। उदाहरण के लिए, अजगर 2.6 में:

import itertools 
import urllib 

def words(): 
    f = urllib.urlopen(
    'http://www.cs.umd.edu/class/fall2008/cmsc433/p5/Usr.Dict.Words.txt') 
    allwords = set(w[:-1] for w in f) 
    f.close() 
    return allwords 

def substrings(s): 
    for i in range(2, len(s)+1): 
    for p in itertools.permutations(s, i): 
     yield ''.join(p) 

def main(): 
    w = words() 
    print '%d words' % len(w) 
    ss = set(substrings('weep')) 
    print '%d substrings' % len(ss) 
    good = ss & w 
    print '%d good ones' % len(good) 
    sgood = sorted(good, key=lambda w:(len(w), w)) 
    for aword in sgood: 
    print aword 

main() 

फेंकना होगा:

38617 words 
31 substrings 
5 good ones 
we 
ewe 
pew 
wee 
weep 
बेशक

, के रूप में अन्य प्रतिक्रियाओं ने कहा, उद्देश्यपूर्ण अपने डेटा का आयोजन बहुत तेजी लाने-अप कर सकते हैं अपने क्रम - हालांकि सबसे अच्छा डेटा संगठन एक तेज़ एनाग्राम खोजक के लिए अलग-अलग हो सकता है ... लेकिन यह बड़े पैमाने पर स्वीकृत शब्दों के आपके शब्दकोश की प्रकृति पर निर्भर करेगा (कुछ हज़ारों, जैसे यहां - या लाखों?)। हैश-मैप्स और "हस्ताक्षर" (प्रत्येक शब्द में अक्षरों को क्रमबद्ध करने के आधार पर) पर विचार किया जाना चाहिए, साथ ही & सी की कोशिश करता है।

+1

यह एक छोटी परीक्षण स्ट्रिंग के लिए काम करता है, लेकिन 16-वर्ण वाला व्यक्ति 20 9 2278 9 888000 संभावित सबस्ट्रिंग उत्पन्न करता है। लंबे परीक्षण तारों के लिए, आप संभव पत्र संयोजनों के बजाय वैध प्रविष्टियों से बंधे रहना चाहते हैं। –

6

आपके द्वारा इच्छित डेटा संरचना को Directed Acyclic Word Graph (dawg) कहा जाता है, और इसका वर्णन एंड्रयू एपेल और गाय जैकबसेन ने अपने पेपर "द वर्ल्ड के फास्टेस्ट स्क्रैबल प्रोग्राम" में किया है, दुर्भाग्य से उन्होंने मुफ्त ऑनलाइन उपलब्ध नहीं कराया है। एक एसीएम सदस्यता या विश्वविद्यालय पुस्तकालय इसे आपके लिए प्राप्त करेगा।

मैंने इस डेटा संरचना को कम से कम दो भाषाओं में कार्यान्वित किया है --- यह सरल, कार्यान्वित करने में आसान है, और बहुत तेज़ है।

+0

मुझे इसे Google खोज के पहले पृष्ठ पर मिला :-) – PowerApp101

+0

शायद एक तेज़ है ... देखें http://www.ericsink.com/downloads/faster-scrabble-gordon.pdf –

+0

धन्यवाद @ नॉर्मन और स्टीव उन अद्भुत संसाधनों को इंगित करने के लिए :) – nXqd

0

मेरा मानना ​​है कि this question के उत्तर में रूबी कोड आपकी समस्या का समाधान भी करेगा।

8

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

"getAnagrams" कमांड भी एक ओ (एन) ऑपरेशन है जो यह देखने के लिए शब्दकोश में प्रत्येक शब्द को खोजता है कि यह खोज का सबसेट है या नहीं। getAnagrams कर ("radiotelegraphically") "(एक 20 पत्र शब्द) लगभग 1 सेकंड अपने लैपटॉप पर ले लिया, और 1496 विपर्यय लौटे

# Using the 38617 word dictionary at 
# http://www.cs.umd.edu/class/fall2008/cmsc433/p5/Usr.Dict.Words.txt 
# Usage: getAnagrams("helloworld") 

def containsLetters(subword, word): 
    wordlen = len(word) 
    subwordlen = len(subword) 

    if subwordlen > wordlen: 
     return False 

    word = list(word) 
    for c in subword: 
     try: 
      index = word.index(c) 
     except ValueError: 
      return False 
     word.pop(index) 
    return True 

def getAnagrams(word): 
    output = [] 
    for key in mydict.iterkeys(): 
     if containsLetters(key, word): 
      output.extend(mydict[key]) 

    output.sort(key=len) 
    return output 

f = open("dict.txt") 
wordlist = f.readlines() 
f.close() 

mydict = {} 
for word in wordlist: 
    word = word.rstrip() 
    temp = list(word) 
    temp.sort() 
    letters = ''.join(temp) 

    if letters in mydict: 
     mydict[letters].append(word) 
    else: 
     mydict[letters] = [word] 

एक उदाहरण रन:।

>>> getAnagrams("helloworld") 
>>> ['do', 'he', 'we', 're', 'oh', 'or', 'row', 'hew', 'her', 'hoe', 'woo', 'red', 'dew', 'led', 'doe', 'ode', 'low', 'owl', 'rod', 'old', 'how', 'who', 'rho', 'ore', 'roe', 'owe', 'woe', 'hero', 'wood', 'door', 'odor', 'hold', 'well', 'owed', 'dell', 'dole', 'lewd', 'weld', 'doer', 'redo', 'rode', 'howl', 'hole', 'hell', 'drew', 'word', 'roll', 'wore', 'wool','herd', 'held', 'lore', 'role', 'lord', 'doll', 'hood', 'whore', 'rowed', 'wooed', 'whorl', 'world', 'older', 'dowel', 'horde', 'droll', 'drool', 'dwell', 'holed', 'lower', 'hello', 'wooer', 'rodeo', 'whole', 'hollow', 'howler', 'rolled', 'howled', 'holder', 'hollowed'] 
+0

यह निश्चित रूप से काम पूरा हो जाता है! लेकिन जॉन पिरी की विधि संभवतः अधिक कुशल है? मैं दोनों के साथ खेलूँगा। – PowerApp101

+0

@ 20 वीं शताब्दी लड़का: जॉन पिरी किसी प्रकार की ट्राई का वर्णन करता है, जिसे मैंने पहले से ही हैश टेबल के संभावित प्रतिस्थापन के रूप में सुझाव दिया है। हालांकि, यह अपूर्ण लगता है। वह एच-ई के साथ त्रिभुज चलने का वर्णन करता है, जो "वह" शब्द देता है, लेकिन क्रमपरिवर्तन को उपेक्षा करता है "आह" (मुझे लगता है कि यह एक शब्द है)। – Unknown

+2

@ अज्ञात: मुझे लगता है कि "एएच" सभी "एच" शब्दों के बाद पता चला होगा, यानी जब फंक्शन पेड़ के शीर्ष पर बैकट्रैक होता है और "ई" से शुरू होने वाली शाखा पर चलता है। – PowerApp101

0

मैं खेल किया गया है हाल ही में मेरे फोन पर बहुत सारे वर्डफूड और उत्सुक थे अगर मैं कुछ शब्दों के साथ संभावित शब्दों की सूची देने के लिए आ सकता हूं। निम्नलिखित कोड आपके उपलब्ध स्रोत अक्षरों (* वाइल्डकार्ड के लिए) और एक मास्टर सूची के साथ एक सरणी लेता है स्वीकार्य शब्द (TWL, SOWPODS, आदि) और मैचों की एक सूची उत्पन्न करता है। यह आपके स्रोत अक्षरों से मास्टर सूची में प्रत्येक शब्द को बनाने का प्रयास करके करता है।

मैं अपने कोड लिखने के बाद इस विषय पाया, और यह निश्चित रूप से जॉन पिरी की विधि या DAWG एल्गोरिथ्म के रूप में के रूप में कुशल नहीं है, लेकिन यह अभी भी बहुत जल्दी हो जाता है।

public IList<string> Matches(string sourceLetters, string [] wordList) 
{ 
    sourceLetters = sourceLetters.ToUpper(); 

    IList<string> matches = new List<string>(); 

    foreach (string word in wordList) 
    { 
     if (WordCanBeBuiltFromSourceLetters(word, sourceLetters)) 
      matches.Add(word); 
    } 

    return matches; 
} 


public bool WordCanBeBuiltFromSourceLetters(string targetWord, string sourceLetters) 
{ 
    string builtWord = ""; 

    foreach (char letter in targetWord) 
    { 
     int pos = sourceLetters.IndexOf(letter); 
     if (pos >= 0) 
     { 
      builtWord += letter; 
      sourceLetters = sourceLetters.Remove(pos, 1); 
      continue; 
     } 


     // check for wildcard 
     pos = sourceLetters.IndexOf("*"); 
     if (pos >= 0) 
     { 
      builtWord += letter; 
      sourceLetters = sourceLetters.Remove(pos, 1); 
     } 


    } 

    return string.Equals(builtWord, targetWord); 

} 
संबंधित मुद्दे