3

我有一个算法可以在一组八个字母的单词中找到字谜。实际上,它是将较长单词中的字母按字母顺序排列,对较短的单词一个接一个地执行相同的操作,并查看它们是否存在于较长的单词中,如下所示:

tower = eortw two = otw rot = ort

这里的问题是,如果我ort在里面寻找eortw(或在塔中腐烂),它会找到它,没问题。腐烂在塔内被发现。但是,otw不在里面eortw(或两个在塔中),因为中间有 R。因此,它认为在塔中找不到两个。

有没有更好的方法可以做到这一点?我正在尝试在 Objective-C 中执行此操作,并且八个字母的单词和常规单词都存储在NSDictionaries(以其正常和按字母顺序排列的形式)中。

我看过其他各种帖子。StackOverflow 上的字谜,但似乎没有一个解决这个特定问题。

这是我到目前为止所拥有的:

- (BOOL) doesEightLetterWord: (NSString* )haystack containWord: (NSString *)needle {
    for (int i = 0; i < [needle length] + 1; i++) {
        if (!needle) {
            NSLog(@"DONE!");
        }

        NSString *currentCharacter = [needle substringWithRange:NSMakeRange(i, 1)];
        NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: currentCharacter];
        NSLog(@"Current character is %@", currentCharacter);
        if ([haystack rangeOfCharacterFromSet:set].location == NSNotFound) {
            NSLog(@"The letter %@ isn't found in the word %@", currentCharacter,    haystack);
            return FALSE;
        } else {
            NSLog(@"The letter %@ is found in the word %@", currentCharacter, haystack);
            int currentLocation = [haystack rangeOfCharacterFromSet: set].location;
            currentLocation++;    
            NSString *newHaystack = [haystack substringFromIndex: currentLocation];
            NSString *newNeedle = [needle substringFromIndex: i + 1];
            NSLog(@"newHaystack is %@", newHaystack);
            NSLog(@"newNeedle is %@", newNeedle);
        }
    }
}
4

3 回答 3

1

如果您仅使用部分字母,则它不是真正的字谜。

在您的情况下,一个好的算法是获取已排序的字符串并逐字母比较它们,跳过较长单词中的不匹配。如果您到达较短单词的末尾,那么您有一个匹配项:

char *p1 = shorter_word;
char *p2 = longer_word;
int match = TRUE;
for (;*p1; p1++) {
  while (*p2 && (*p2 != *p1)) {
    p2++;
  }
  if (!*p2) {
    /* Letters of shorter word are not contained in longer word */
    match = FALSE;
  }
}
于 2012-11-14T14:17:43.837 回答
0

这是我可能会采用的一种方法来确定一个有序词是否包含另一个有序词的所有字母。请注意,它不会找到真正的字谜(这只需要两个有序字符串相同),但这符合我认为您所要求的:

+(BOOL) does: (NSString* )longWord contain: (NSString *)shortWord {
    NSString *haystack = [longWord copy];
    NSString *needle = [shortWord copy];
    while([haystack length] > 0 && [needle length] > 0) {
        NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString: [needle substringToIndex:1]];
        if ([haystack rangeOfCharacterFromSet:set].location == NSNotFound) {
            return NO;
        }
        haystack = [haystack substringFromIndex: [haystack rangeOfCharacterFromSet: set].location+1];
        needle = [needle substringFromIndex: 1];
    }

    return YES;
}
于 2012-11-14T14:24:02.183 回答
0

最简单(但不是最有效)的方法可能是使用NSCountedSet. 我们可以这样做,因为对于计数集,[a isSubsetOfSet:b]当且仅当[a countForObject:object] <= [b countForObject:object]for each objectin时才返回 YES a

让我们添加一个类别来NSString做到这一点:

@interface NSString (lukech_superset)

- (BOOL)lukech_isSupersetOfString:(NSString *)needle;

@end

@implementation NSString (lukech_superset)

- (NSCountedSet *)lukech_countedSetOfCharacters {
    NSCountedSet *set = [NSCountedSet set];
    [self enumerateSubstringsInRange:NSMakeRange(0, self.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        [set addObject:substring];
    }];
    return set;
}

- (BOOL)lukech_isSupersetOfString:(NSString *)needle {
    return [[needle lukech_countedSetOfCharacters] isSubsetOfSet:[self lukech_countedSetOfCharacters]];
}

@end
于 2012-11-14T19:41:52.510 回答