-->

从阵列重新排列字母,并检查是否布置在阵列(Rearrange Letters from Array

2019-08-20 03:17发布

我在做一个iOS应用程序,你输入9个lettes和那些9个字母它将输出字谜。 它像目标单词,或在纸张9字母的单词。 像这样的链接:

http://nineletterword.tompaton.com/

它不只是提供字谜为9个字母,它会做它的4个字母,5个字母,6个字母......所有这些都至少包含字母中间。

我想使它离线应用程序,所以我不想引用任何网站或使用在线JSON ...

我怎么会去检查,如果9个字母组成的数组可以重新整理成一个词是在我已经下载了一本英语词典。

例如我的(A,B,A,N,d,O,N,E,d)输入:我将如何得到的4个字母或多种有利于所谓的“英语词典”的阵列的英语单词,其输出必须包含中间的字母“d” - 像“放弃”,“债券”,“死” ...

是最好的方法很多,很多循环和if语句或者是有什么在Xcode / Objective C的,我可以用先手的4个字母列表,然后有这一切成为可能的安排...

干杯

Answer 1:

让我提出一个不同的算法依赖于一个查询,而不是通过一个数组的搜索。

建立:

遍历字典中的单词。 对于每一个字,创建具有相同的字符,按字母顺序排序的字符串。 使用这个字符串作为重点,创建的原话阵列的字典。

用法:

现在你可以做任何字符组合的检查非常快:就像上面的字符排序和查找产生的向上键在地图。

例:

原始阵列: ( bond, Mary, army )

字谜查找图:

{
   bdno : ( bond ),
   amry : ( Mary, army ),
}

使用这种地图是非常快的检查任何字的字谜。 需要字典阵列上没有迭代。

编辑:

我的算法拆分分为三个部分:

  1. 甲设置方法来构建从对象的字典中查找图: anagramMap
  2. 计算字符一个字符的方法来分类的关键: anagramKey
  3. 该发现包含在九个字母的单词中的字符的所有排列和查找在地图上的字的算法: findAnagrams

这里有三种方法作为一个类的实现NSString

@interface NSString (NSStringAnagramAdditions)
- (NSSet *)findAnagrams;
@end

@implementation NSString (NSStringAnagramAdditions)

+ (NSDictionary *)anagramMap
{
    static NSDictionary *anagramMap;
    if (anagramMap != nil)
        return anagramMap;

    // this file is present on Mac OS and other unix variants
    NSString *allWords = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                   encoding:NSUTF8StringEncoding
                                                      error:NULL];

    NSMutableDictionary *map = [NSMutableDictionary dictionary];
    @autoreleasepool {
        [allWords enumerateLinesUsingBlock:^(NSString *word, BOOL *stop) {
            NSString *key = [word anagramKey];
            if (key == nil)
                return;
            NSMutableArray *keyWords = [map objectForKey:key];
            if (keyWords == nil) {
                keyWords = [NSMutableArray array];
                [map setObject:keyWords forKey:key];
            }
            [keyWords addObject:word];
        }];
    }

    anagramMap = map;
    return anagramMap;
}

- (NSString *)anagramKey
{
    NSString *lowercaseWord = [self lowercaseString];

    // make sure to take the length *after* lowercase. it might change!
    NSUInteger length = [lowercaseWord length];

    // in this case we're only interested in anagrams 4 - 9 characters long
    if (length < 4 || length > 9)
        return nil;

    unichar sortedWord[length];
    [lowercaseWord getCharacters:sortedWord range:(NSRange){0, length}];

    qsort_b(sortedWord, length, sizeof(unichar), ^int(const void *aPtr, const void *bPtr) {
        int a = *(const unichar *)aPtr;
        int b = *(const unichar *)bPtr;
        return b - a;
    });

    return [NSString stringWithCharacters:sortedWord length:length];
}

- (NSSet *)findAnagrams
{
    unichar nineCharacters[9];
    NSString *anagramKey = [self anagramKey];

    // make sure this word is not too long/short.
    if (anagramKey == nil)
        return nil;
    [anagramKey getCharacters:nineCharacters range:(NSRange){0, 9}];
    NSUInteger middleCharPos = [anagramKey rangeOfString:[self substringWithRange:(NSRange){4, 1}]].location;

    NSMutableSet *anagrams = [NSMutableSet set];

    // 0x1ff means first 9 bits set: one for each character
    for (NSUInteger i = 0; i <= 0x1ff; i += 1) {

        // skip permutations that do not contain the middle letter
        if ((i & (1 << middleCharPos)) == 0)
            continue;

        NSUInteger length = 0;
        unichar permutation[9];
        for (int bit = 0; bit <= 9; bit += 1) {
            if (i & (1 << bit)) {
                permutation[length] = nineCharacters[bit];
                length += 1;
            }
        }

        if (length < 4)
            continue;

        NSString *permutationString = [NSString stringWithCharacters:permutation length:length];
        NSArray *matchingAnagrams = [[self class] anagramMap][permutationString];

        for (NSString *word in matchingAnagrams)
            [anagrams addObject:word];
    }

    return anagrams;
}

@end

假设在一个变量称为测试字符串nineletters你会登录使用的可能值:

for (NSString *anagram in [nineletters findAnagrams])
    NSLog(@"%@", anagram);


Answer 2:

首先,你需要一种方法来检查,如果一个字是第二个字的字谜。 有许多可能的解决方案(搜索“的Objective-C字谜”)。 这实质上是从方法https://stackoverflow.com/a/13465672/1187415 ,书面略有不同:

- (BOOL)does:(NSString*)longWord contain:(NSString *)shortWord
{
    NSMutableString *longer = [longWord mutableCopy];
    __block BOOL retVal = YES;
    // Loop over all characters (letters) in shortWord:
    [shortWord enumerateSubstringsInRange:NSMakeRange(0, [shortWord length])
                                  options:NSStringEnumerationByComposedCharacterSequences
                               usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        // Check if letter occurs in longer word:
        NSRange letterRange = [longer rangeOfString:substring];
        if (letterRange.location != NSNotFound) {
            // Yes. Remove from longer word and continue.
            [longer deleteCharactersInRange:letterRange];
        } else {
            // No. Set return value to NO and quit the loop.
            retVal = NO;
            *stop = YES;
        }
    }];
    return retVal;
}

例子:

  • [self does:@"abandoned" contain:@"bond"] = YES
  • [self does:@"abandoned" contain:@"sea"] = NO ,因为没有“S”的第一个字。
  • [self does:@"abandoned" contain:@"noon"] = NO ,因为“中午”具有2个字母“o”的,但第一个字仅具有一个“O”。

然后,你可以进行如下操作:

NSArray *englishWords = ...; // Your array of english words

NSString *inputWord = @"abandoned"; // The input string
NSString *middleLetter = [inputWord substringWithRange:NSMakeRange([inputWord length]/2, 1)];

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString *word, NSDictionary *bindings) {
    // Word must have at least 4 letters:
    if ([word length] < 4)
        return NO;
    // Word must contain the middle letter:
    if ([word rangeOfString:middleLetter].location == NSNotFound)
        return NO;
    // Word must contain only letters of the input word:
    if (![self does:inputWord contain:word])
        return NO;
    return YES;
}];
NSArray *matchingWords = [englishWords filteredArrayUsingPredicate:predicate];
NSLog(@"%@", matchingWords);


文章来源: Rearrange Letters from Array and check if arrangement is in array