我一直试图在项目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
的范围超出范围,但我不知道它是怎么回事,因为上限和下限都应该是动态的,并为每个和每个号码,对吗?
任何帮助将不胜感激!
答案 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
开始的子字符串的长度。
如果字符串为location
而1234
为half
,那么2
为字符2 - 6,那就是超出界限。
计算其余字符,例如
NSRange(2, 4)
答案 3 :(得分:1)
我认为你可能会误解NSRange
和NSMakeRange
。 NSMakeRange
的两个参数是范围的起始位置和长度,而不是起始位置和结束位置。如果你做了这个改变:
//NSString *part2 = [number substringWithRange:NSMakeRange(half, [number length])];//old line
NSString *part2 = [number substringWithRange:NSMakeRange(half, [number length] - half)];//new line
然后你应该消除越界错误。
作为旁注,你的回文检查逻辑存在一些问题。在检查相等性之前,您必须镜像字符串的第二部分(请注意如何使用字符串执行此操作)。你还需要更复杂一些来处理奇数位的数字。