范围超出界限,Project Euler 4

时间:2015-12-30 17:14:20

标签: objective-c

我一直试图在项目Euler上解决问题4:

  

回文数字两种方式相同。由两个2位数字的乘积制成的最大回文率是9009 = 91×99。

     

找出由两个3位数字的乘积制成的最大回文。

我一直在使用Objective-C这样做,我认为我已经提出了一个解决方案但由于某种原因我得到了Thread 1: signal SIGABRT - 错误了一点,我希望你们能帮助我弄清楚我的代码有什么问题:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableArray *palindromes = [[NSMutableArray alloc] init];

    for (int i = 1; i < 1000; i++) {
        for (int j = 1; j < 1000; j++) {
            int k = i * j;

            NSString *number = [NSString stringWithFormat:@"%d", k];
            NSUInteger length = [number length];
            NSUInteger half = (length / 2);

            NSString *part1 = [number substringWithRange:NSMakeRange(0, half)];

            //It's at the line below that I get the error
            NSString *part2 = [number substringWithRange:NSMakeRange(half, [number length])];

            if (part1 == part2) {
                [palindromes addObject:number];
            }
        }
    }
    for (int l = 0; l < [palindromes count]; l++) {
        NSLog(@"%d", l);
    }
}
return 0;
}

我希望我的代码要做的是将前1乘以1,2,3,... 999,然后将其与2,3,4等相同,直到999.对于每次迭代,数字当前乘法的数据将存储在k中。然后将k转换为名为number的NSString。然后number的长度和一半长度分别存储在变量length half中。然后将当前数字的前半部分存储在NSString part1中,将后半部分存储在NSString part2中。然后我比较这两个子串,如果它们相等,它们会被添加到palindrome - 数组中,然后打印出数组。

但是,当我尝试在Xcode中运行它时,当它到达我在代码中标记的行时会停止并向我抛出Thread 1: signal SIGABRT - 错误。控制台中的输出如下所示:

2015-12-30 17:26:41.522 Euler4[2075:167976] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[NSTaggedPointerString substringWithRange:]: Range {1, 2} out of bounds; string length 2'
*** First throw call stack:
(
0   CoreFoundation                      0x00007fff8e6a9ae2 __exceptionPreprocess + 178
1   libobjc.A.dylib                     0x00007fff8a202f7e objc_exception_throw + 48
2   CoreFoundation                      0x00007fff8e6a998d +[NSException raise:format:] + 205
3   CoreFoundation                      0x00007fff8e644cfa -[NSTaggedPointerString substringWithRange:] + 394
4   Euler4                              0x00000001000013fb main + 507
5   libdyld.dylib                       0x00007fff946b85ad start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

我确实得到的问题是part2的范围超出范围,但我不知道它是怎么回事,因为上限和下限都应该是动态的,并为每个和每个号码,对吗?

任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:2)

你应该这样做:

NSString *part2 = [number substringWithRange:NSMakeRange(half, half)];

因为你从half开始,你需要阅读下半年(然后是长度)。

但您检查回文的代码不正确。

更正的代码应为:

NSMutableArray * palindromes = [[NSMutableArray alloc] init];

for (int i = 1; i < 1000; i++) {
    for (int j = 1; j < 1000; j++) {
        int k = i * j;

        NSString *number = [NSString stringWithFormat:@"%d", k];
        NSUInteger length = [number length];
        NSUInteger half = (length / 2);

        NSString *part1 = [number substringWithRange:NSMakeRange(0, half)];

        NSString *part2 = [number substringWithRange:NSMakeRange(half, half)];
        NSMutableString *reverseStringPart2 = [NSMutableString stringWithCapacity:[part2 length]];

        //following blocks reverses the part2 and store it in reverseStringPart2
        [part2 enumerateSubstringsInRange:NSMakeRange(0,[part2 length])
                                     options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
                                  usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                      [reverseStringPart2 appendString:substring];
                                  }];


        //note == is not used since you needed to compare two strings value not their addresses
        if ([part1 isEqualToString:reverseStringPart2]) {
            [palindromes addObject:number];
        }
    }
}

修改 因为你想要找到由两个3位数字的多重复制形成的最大回文数。这可以简单地完成:

for (int k = 999*999; k > 0; k--) {
        NSString *number = [NSString stringWithFormat:@"%d", k];
        NSUInteger length = [number length];
        NSUInteger half = (length / 2);

        NSString *part1 = [number substringWithRange:NSMakeRange(0, half)];

        NSString *part2 = [number substringWithRange:NSMakeRange(half, half)];
        NSMutableString *reverseStringPart2 = [NSMutableString stringWithCapacity:[part2 length]];

        [part2 enumerateSubstringsInRange:NSMakeRange(0,[part2 length])
                                     options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
                                  usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                      [reverseStringPart2 appendString:substring];
                                  }];



        if ([part1 isEqualToString:reverseStringPart2]) {
            NSLog(@"The largest palindrome of multiplicatin of two 3-digits number is:  %@", number);
            break;

        }
    }

*注意:您可以在不创建字符串和进行操作的情况下找到上述内容。只需创建一个整数,并使用数学逻辑,您可以检查它是否是回文。从999 * 999开始向1.移动。你找到的第一个是结果,然后打破循环。*

答案 1 :(得分:1)

NSMakeRange的论据是location length 。如果您将location设置为half,那么length的最大合法值为number.length - half。但是如果你改为使用它,那么对于一个奇数长度的字符串,你将获得part2而不是part1中的中间字符。实际上,您希望将第二个NSRange创建为NSMakeRange(number.length - half, half)

您的下一个问题是,您永远找不到回文,因为您正在使用part1 == part2测试字符串相等,但您需要使用[part1 isEqualToString:part2]进行测试。

解决之后,你会发现你的回文测试是错误的。您的测试将通过123123,但123123不是回文。您需要测试[number isEqualToString: number.reversed]。 (你根本不必弄乱NSMakeRange!)但reversed上没有NSString属性,所以you'll have to write your own code to reverse the string.

顺便提一下,您也可以在100而不是1开始循环,因为问题是“两个3位数的乘积”,而1 ... 99范围内的数字不是3位数。< / p>

答案 2 :(得分:1)

结构length的{​​{1}}成员表示从第一个成员NSRange开始的子字符串的长度。

如果字符串为location1234half,那么2为字符2 - 6,那就是超出界限。

计算其余字符,例如

NSRange(2, 4)

答案 3 :(得分:1)

我认为你可能会误解NSRangeNSMakeRangeNSMakeRange的两个参数是范围的起始位置和长度,而不是起始位置和结束位置。如果你做了这个改变:

//NSString *part2 = [number substringWithRange:NSMakeRange(half, [number length])];//old line
NSString *part2 = [number substringWithRange:NSMakeRange(half, [number length] - half)];//new line

然后你应该消除越界错误。

作为旁注,你的回文检查逻辑存在一些问题。在检查相等性之前,您必须镜像字符串的第二部分(请注意如何使用字符串执行此操作)。你还需要更复杂一些来处理奇数位的数字。