【问题标题】:Permutations/Anagrams in Objective-C -- I am missing somethingObjective-C 中的排列/字谜——我遗漏了一些东西
【发布时间】:2011-07-07 21:14:56
【问题描述】:

(下面关于我的问题的代码)

根据this stack overflow question,我使用 Pegolon 的方法在 NSString 中生成一组字符的所有可能排列。但是,我现在试图让它不仅生成一个 ANAGRAM,它是所有相同长度的排列,而且是字符串中字符的所有可能组合(任何长度)。

有人知道我将如何更改以下代码以使其执行此操作吗?这很像:Generate All Permutations of All Lengths——但是(因为害怕他们需要回答家庭作业)他们没有留下代码。我在这篇文章的底部有一个我认为会做的样本......但它没有。

因此,当给定THE 时,代码会按原样生成thetehhtehetetheht。 我需要的是:t,h,e,th,ht,te,he(等)除了上述3个字符组合。

请问我该如何更改。 (ps:这里有两种方法。我添加了allPermutationsArrayofStrings,以便将结果作为字符串返回,就像我想要的那样,而不仅仅是另一个数组中的字符数组)。我假设魔法会在pc_next_permutation 发生——但我想我会提到它。

在 NSArray+Permutation.h 中

#import <Foundation/Foundation.h>

@interface NSArray(Permutation)
- (NSArray *)allPermutationsArrayofArrays;
- (NSArray *)allPermutationsArrayofStrings;

@end

在 NSArray+Permutation.m 中:

#define MAX_PERMUTATION_COUNT   20000

NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size);
NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size) 
{
    // slide down the array looking for where we're smaller than the next guy
    NSInteger pos1;
    for (pos1 = size - 1; perm[pos1] >= perm[pos1 + 1] && pos1 > -1; --pos1);

    // if this doesn't occur, we've finished our permutations
    // the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
    if (pos1 == -1)
        return NULL;

    assert(pos1 >= 0 && pos1 <= size);

    NSInteger pos2;
    // slide down the array looking for a bigger number than what we found before
    for (pos2 = size; perm[pos2] <= perm[pos1] && pos2 > 0; --pos2);

    assert(pos2 >= 0 && pos2 <= size);

    // swap them
    NSInteger tmp = perm[pos1]; perm[pos1] = perm[pos2]; perm[pos2] = tmp;

    // now reverse the elements in between by swapping the ends
    for (++pos1, pos2 = size; pos1 < pos2; ++pos1, --pos2) {
        assert(pos1 >= 0 && pos1 <= size);
        assert(pos2 >= 0 && pos2 <= size);

        tmp = perm[pos1]; perm[pos1] = perm[pos2]; perm[pos2] = tmp;
    }

    return perm;
}

@implementation NSArray(Permutation)

- (NSArray *)allPermutationsArrayofArrays
{
    NSInteger size = [self count];
    NSInteger *perm = malloc(size * sizeof(NSInteger));

    for (NSInteger idx = 0; idx < size; ++idx)
        perm[idx] = idx;

    NSInteger permutationCount = 0;

    --size;

    NSMutableArray *perms = [NSMutableArray array];

    do {
        NSMutableArray *newPerm = [NSMutableArray array];

        for (NSInteger i = 0; i <= size; ++i)
            [newPerm addObject:[self objectAtIndex:perm[i]]];

        [perms addObject:newPerm];
    } while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
    free(perm);

    return perms;
}

- (NSArray *)allPermutationsArrayofStrings
{
    NSInteger size = [self count];
    NSInteger *perm = malloc(size * sizeof(NSInteger));

    for (NSInteger idx = 0; idx < size; ++idx)
        perm[idx] = idx;

    NSInteger permutationCount = 0;

    --size;

    NSMutableArray *perms = [NSMutableArray array];

    do {
        NSMutableString *newPerm = [[[NSMutableString alloc]initWithString:@"" ]autorelease];

        for (NSInteger i = 0; i <= size; ++i)
        {
            [newPerm appendString:[self objectAtIndex:perm[i]]];
        }
        [perms addObject:newPerm];
    } while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
    free(perm);

    return perms;
}

@end

我认为可以解决此问题的代码:

for ( NSInteger i = 1; i <= theCount; i++) {
                NSRange theRange2;
                theRange2.location = 0;
                theRange2.length = i;
                NSLog(@"Location: %i (len: %i) is: '%@'",theRange2.location,theRange2.length,[array subarrayWithRange:theRange2]);

                NSArray *allWordsForThisLength = [[array subarrayWithRange:theRange2] allPermutationsArrayofStrings];
                for (NSMutableString *theString in allWordsForThisLength)
                {
                    NSLog(@"Adding %@ as a possible word",theString);
                    [allWords addObject:theString];
                }

我知道这不是最有效的..但我正在尝试测试。

这是我得到的:

2011-07-07 14:02:19.684 TA[63623:207] Total letters in word: 3
2011-07-07 14:02:19.685 TA[63623:207] Location: 0 (len: 1) is: '(
    t
)'
2011-07-07 14:02:19.685 TA[63623:207] Adding t as a possible word
2011-07-07 14:02:19.686 TA[63623:207] Location: 0 (len: 2) is: '(
    t,
    h
)'
2011-07-07 14:02:19.686 TA[63623:207] Adding th as a possible word
2011-07-07 14:02:19.687 TA[63623:207] Adding ht as a possible word
2011-07-07 14:02:19.688 TA[63623:207] Location: 0 (len: 3) is: '(
    t,
    h,
    e
)'
2011-07-07 14:02:19.688 TA[63623:207] Adding the as a possible word
2011-07-07 14:02:19.689 TA[63623:207] Adding teh as a possible word
2011-07-07 14:02:19.690 TA[63623:207] Adding hte as a possible word
2011-07-07 14:02:19.691 TA[63623:207] Adding het as a possible word
2011-07-07 14:02:19.691 TA[63623:207] Adding eth as a possible word
2011-07-07 14:02:19.692 TA[63623:207] Adding eht as a possible word

如您所见,没有一两个字母的单词——我要拔头发了! (而且我没有太多空闲!)

【问题讨论】:

  • 这是作业吗?如果是这样,请将其标记为这样,以便我们知道如何最好地帮助您。
  • 不,这不是家庭作业。我几乎希望是这样。会表明我比我年轻得多...我正在为需要此例程的 IOS 编写程序。
  • 你确实有几个一两个字母的单词。我看到“t”,我看到“th”和“ht”
  • 我应该换种说法......我的意思是(在这种情况下)你永远不会看到HE,因为在你到达E之前,@987654345 @ 已经添加到要输出的单词中......因此您不会得到由原始单词中的第三个或后面的字母组成的两个字母的单词。这是我能做的最好的解释。

标签: iphone objective-c ios sdk permutation


【解决方案1】:

一个简单的做法是获取大小为k 的所有子集,并使用您必须生成子集的所有排列的代码。这很简单,但不是最有效的。


这里有一个更好的方法。您在第一个例程中按字典顺序生成排列:

1234
1243
1324
1342
1423
...

每次调用NSInteger *pc_next_permutation(NSInteger *perm, const NSInteger size) 时,您都会通过找到要更改的正确位置来获得按 lex 顺序排列的下一个排列。当您这样做时,从您更改的位置截断以获得以下内容:

1234 123 12 1
1243 124
1324 132 13
1342 134
1423 142 14
1432 143
2143 214 21 2
...

我希望这个想法很清楚。这是实现这一点的一种方法(在类似于 Objective C 的伪代码中)。

-(NSMutableArray *)nextPerms:(Perm *)word {
    int N = word.length;
    for (int i=N-1; i > 0; ++i) {
        if (word[i-1] < word[i]) {
            break;
        } else if (i==1) {
            i = 0;
        }
    }
    // At this point, i-1 is the leftmost position that will change
    if (i == 0) {
        return nil;
    }
    i = i-1;
    // At this point, i is the leftmost position that will change
    Perm *nextWord = word;
    for (int j=1; j <= N-i; ++j) {
        nextWord[i+j] = word[N-j];
    }
    nextWord[i] = nextWord[i+1];
    nextWord[i+1] = word[i];

    // At this point, nextPerm is the next permutation in lexicographic order.    

    NSMutableArray *permList = [[NSMutableArray alloc] init];
    for (int j=i; j<N; ++j) {
        [permList addObject:[nextWord subwordWithRange:NSMakeRange(0,i)]];
    }
    return [permList autorelease];
}

这将返回一个具有上述部分排列的数组。 nextPerms 的输入应该是nextPerms 输出的lastObject

【讨论】:

  • 不是真的。因为如果您使用 THE 作为您的词,则大小为 K 的子集仍将仅使用我的代码返回大小为 K 的结果。如果我错了,请告诉我。
  • @Jann:是的,我建议对 k=1,2,...,N 执行此操作,其中 N 是字符串的长度。
  • 这就是我对帖子的“补充”表明......我试图解决它:) 但是,问题是它不是我的原始代码,所以我试图将其理解为好吧,我失败了……这就是我拔头发的原因。我不知道在pc_next_permutation 的哪个地方做你说的。听起来它会解决它,但对我来说问题是“如何”。你能不能再给我一点帮助?
  • 你能看一下我想出的解决方案,看看它是否反映了你的建议吗?如果是这样,我会 +1 并检查你的答案...
  • @Jann:见我上面的代码。这将为您提供我建议的部分排列。我没有测试这段代码,所以我的语法和内存管理可能是关闭的,但这应该让你知道如何继续。
【解决方案2】:

好的,

现在很沮丧,但是,这就是我所做的......

我把NSArray+Permutations.m改成如下:

- (NSArray *)allPermutationsArrayofStrings
{
    NSInteger size = [self count];
    NSInteger *perm = malloc(size * sizeof(NSInteger));

    for (NSInteger idx = 0; idx < size; ++idx)
        perm[idx] = idx;

    NSInteger permutationCount = 0;

    --size;

    NSMutableArray *perms = [NSMutableArray array];
    NSMutableDictionary *permsDict = [[NSMutableDictionary alloc] init];

    do {
        NSMutableString *newPerm = [[[NSMutableString alloc]initWithString:@"" ]autorelease];

        for (NSInteger i = 0; i <= size; ++i)
        {
            [newPerm appendString:[self objectAtIndex:perm[i]]];
        }

        if ([permsDict objectForKey:newPerm] == nil)
        {
            [permsDict setObject:@"1" forKey:newPerm];
            [perms addObject:newPerm];
        }

        for (NSInteger i = 1; i <= [newPerm length]; ++i)
        {
            NSRange theRange;
            theRange.location = 0;
            theRange.length = i;
            if ([permsDict objectForKey:[newPerm substringToIndex:i]] ==  nil)
            {
                [permsDict setObject:@"1" forKey:[newPerm substringToIndex:i]];
                [perms addObject:[newPerm substringToIndex:i]];
            }
        }

    } while ((perm = pc_next_permutation(perm, size)) && ++permutationCount < MAX_PERMUTATION_COUNT);
    free(perm);

    [permsDict release];

    return perms;
}

主要的变化是@PengOne 的想法...返回结果词法更改的字符串,但也一次将其缩短 1 个字符,如果它不存在,则将其添加到返回的数组中。

我选择“便宜”并使用NSMutableDictionary 进行跟踪。因此,如果字典中没有列出词法更改的字符串,则将其添加。

这或多或少是你认为我应该做的吗,@PengOne?

比将它们全部添加并稍后处理生成的重复项要快得多——而且我认为它的工作原理就像我需要的那样。

【讨论】:

  • 或多或少。我(新添加的)代码中的方法将完全避免重复,这样可以节省一些时间。
猜你喜欢
  • 1970-01-01
  • 2013-07-12
  • 2011-05-14
  • 1970-01-01
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 2021-04-25
  • 2019-03-12
相关资源
最近更新 更多