Objective-C 练习题,题目来源 exercism.io,一共 50 题,见 GitHub

第四篇共 10 题。

(一)
(二)
(三)
(五)

# Allergies

题目和测试用例见链接,下同。Allergies
Given a person’s allergy score, determine whether or not they’re allergic to a given item, and their full list of allergies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Allergies.h
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, Allergy) {
AllergenEggs = 1,
AllergenPeanuts = 2,
AllergenShellfish = 4,
AllergenStrawberries = 8,
AllergenTomatoes = 16,
AllergenChocolate = 32,
AllergenPollen = 64,
AllergenCats = 128,
};

@interface Allergies : NSObject

- (instancetype)initWithScore:(NSInteger)score;
- (BOOL)hasAllergy:(Allergy)allergy;

@end

// Allergies.m
#import "Allergies.h"

@implementation Allergies {
NSInteger _kScore;
}

- (instancetype)initWithScore:(NSInteger)score {
if (self = [super init]) {
_kScore = score;
}
return self;
}

- (BOOL)hasAllergy:(Allergy)allergy {
return (_kScore & allergy);
}

@end

# Meetup

Meetup
Calculate the date of meetups.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Meetup.h
#import <Foundation/Foundation.h>


typedef NS_ENUM(NSUInteger, MeetupDay) {
MeetupDayOfWeekSunday = 1,
MeetupDayOfWeekMonday,
MeetupDayOfWeekTuesday,
MeetupDayOfWeekWednesday,
MeetupDayOfWeekThursday,
MeetupDayOfWeekFriday,
MeetupDayOfWeekSaturday,
};

typedef NS_ENUM(NSUInteger, MeetupOption) {
MeetupOptionsFirst = 0,
MeetupOptionsSecond = 7,
MeetupOptionsThird = 14,
MeetupOptionsFourth = 21,
MeetupOptionsLast,
MeetupOptionsTeenth,
};

@interface Meetup : NSObject

- (instancetype)initWithYear:(NSInteger)year andMonth:(NSInteger)month;
- (NSDate *)dayForDayOfWeek:(MeetupDay)dayOfWeek andOptions:(MeetupOption)option;

@end

// Meetup.m
#import "Meetup.h"

@interface Meetup ()

@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger month;
@property (nonatomic, assign) NSInteger day;

@end

@implementation Meetup

- (instancetype)initWithYear:(NSInteger)year andMonth:(NSInteger)month {
if (self = [super init]) {
self.year = year;
self.month = month;
}
return self;
}

- (NSDate *)dayForDayOfWeek:(MeetupDay)dayOfWeek andOptions:(MeetupOption)option {
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = self.year;
components.month = self.month;
components.day = 1;

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:NSCalendarUnitWeekday fromDate:[calendar dateFromComponents:components]];
NSInteger day = 1;
// first dayOfWeek
if (dayOfWeek >= dateComponents.weekday) {
day += (dayOfWeek - dateComponents.weekday);
} else {
day += (dayOfWeek + 7 - dateComponents.weekday);
}

if (option == MeetupOptionsLast) {
NSInteger days = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:[calendar dateFromComponents:components]].length; // days in month
if (day + 28 > days) {
day += 21;
} else {
day += 28;
}
} else if (option == MeetupOptionsTeenth) {
if (dayOfWeek >= dateComponents.weekday && dateComponents.weekday != 1) {
day += 14;
} else {
day += 7;
}
} else {
day += option;
}

components.day = day;
return [calendar dateFromComponents:components];
}

@end

# Anagram

Anagram
Given a word and a list of possible anagrams, select the correct sublist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Anagram.h
#import <Foundation/Foundation.h>

@interface Anagram : NSObject

- (instancetype)initWithString:(NSString *)string;
- (NSArray *)match:(NSArray *)lists;

@end

// Anagram.m
#import "Anagram.h"

@interface Anagram ()

@property (nonatomic, copy) NSString *string;

@end

@implementation Anagram

- (instancetype)initWithString:(NSString *)string {
if (self = [super init]) {
self.string = string;
}
return self;
}

- (NSArray *)match:(NSArray *)lists {
NSMutableArray *result = [NSMutableArray array];
[lists enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *string1 = [obj lowercaseString];
NSString *string2 = [self.string lowercaseString];
if (string1.length == string2.length && ![string1 isEqualToString:string2]) {
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *array2 = [NSMutableArray array];
for (NSInteger i = 0; i < obj.length; ++i) {
[array addObject:[string1 substringWithRange:NSMakeRange(i, 1)]];
[array2 addObject:[string2 substringWithRange:NSMakeRange(i, 1)]];
}
[array sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return [obj1 compare:obj2];
}];
[array2 sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
return [obj1 compare:obj2];
}];
if ([array isEqualToArray:array2]) {
[result addObject:obj];
}
}
}];
return result;
}

@end

# Acronym

Acronym
Convert a long phrase to its acronym

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Acronym.h
#import <Foundation/Foundation.h>

@interface Acronym : NSObject

+ (NSString *)abbreviate:(NSString *)input;

@end

// Acronym.m
#import "Acronym.h"

@implementation Acronym

+ (NSString *)abbreviate:(NSString *)input {
input = [input stringByReplacingOccurrencesOfString:@"[^a-zA-Z ]" withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, input.length)];
__block NSString *result = @"";
[input enumerateSubstringsInRange:NSMakeRange(0, input.length) options:NSStringEnumerationByWords usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
result = [result stringByAppendingString:[[substring substringToIndex:1] uppercaseString]];
for (NSInteger i = 1; i < substring.length; ++i) {
NSString *subStr = [substring substringWithRange:NSMakeRange(i, 1)];
NSString *subStr2 = [substring substringWithRange:NSMakeRange(i - 1, 1)];
if ([subStr isEqualToString:[subStr uppercaseString]]
&& [subStr2 isEqualToString:[subStr2 lowercaseString]]) {
result = [result stringByAppendingString:subStr];
}
}
}];
return result;
}

@end

# All Your Base

All Your Base
Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// AllYourBase.h
#import <Foundation/Foundation.h>

@interface AllYourBase : NSObject

+ (NSArray *)outputDigitsForInputBase:(NSInteger)inputBase inputDigits:(NSArray *)inputDigits outputBase:(NSInteger)outputBase;

@end

// AllYourBase.m
#import "AllYourBase.h"

@implementation AllYourBase

+ (NSArray *)outputDigitsForInputBase:(NSInteger)inputBase inputDigits:(NSArray *)inputDigits outputBase:(NSInteger)outputBase {
NSAssert(inputBase > 1, @"inputBase > 1");
NSAssert(outputBase > 1, @"outputBase > 1");

NSInteger decimalNumber = 0;
for (NSInteger i = 0; i < inputDigits.count; ++i) {
NSInteger inputDigit = [inputDigits[i] integerValue];
NSAssert(inputDigit < inputBase && inputDigit >= 0, @"inputDigit > 0 && inputDigit < inputBase");
decimalNumber += (inputDigit * pow(inputBase, inputDigits.count - i - 1));
}

NSInteger index = 0;
for (; ; ++index) {
if (pow(outputBase, index) > decimalNumber) {
index--;
break;
}
}

NSMutableArray *result = [NSMutableArray array];
while (index >= 0) {
NSInteger value = pow(outputBase, index);
NSInteger digit = 0;
if (value > decimalNumber) {
value = 0;
} else {
digit = decimalNumber / value;
}
[result addObject:@(digit)];
decimalNumber -= (value * digit);
index--;
}

return result;
}

@end

# Largest Series Product

Largest Series Product
Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// LargestSeriesProduct.h
#import <Foundation/Foundation.h>

@interface LargestSeriesProduct : NSObject

- (instancetype)initWithNumberString:(NSString *)string;
- (long)largestProduct:(NSInteger)product;

@end

// LargestSeriesProduct.m
#import "LargestSeriesProduct.h"

@interface LargestSeriesProduct ()

@property (nonatomic, copy) NSString *string;

@end

@implementation LargestSeriesProduct

- (instancetype)initWithNumberString:(NSString *)string {
if (self = [super init]) {
self.string = string;
}
return self;
}

- (long)largestProduct:(NSInteger)length {
NSAssert(self.string.length >= length && length >= 0, @"length <= string.length && length >= 0");
NSAssert(([[NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"^[0-9]*$"] evaluateWithObject:self.string]), @"String contains non-numeric");
if (length == 0) {
return 1;
}
long largestProduct = 0;
for (NSInteger i = 0; i <= self.string.length - length; ++i) {
NSString *substring = [self.string substringWithRange:NSMakeRange(i, length)];
if ([substring containsString:@"0"]) {
continue;
}
__block long product = 1;
[substring enumerateSubstringsInRange:NSMakeRange(0, length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
product *= [substring integerValue];
}];
largestProduct = MAX(largestProduct, product);
}
return largestProduct;
}

@end

# Pangram

Pangram
Determine if a sentence is a pangram.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Pangram.h
#import <Foundation/Foundation.h>

@interface Pangram : NSObject

+ (BOOL)isPangram:(NSString *)string;

@end

// Pangram.m
#import "Pangram.h"

@implementation Pangram

+ (BOOL)isPangram:(NSString *)string {
__block NSString *lowercaseString = [string lowercaseString];
NSString *str = @"abcdefghijklmnopqrstuvwxyz";
__block BOOL isPangram = YES;
[str enumerateSubstringsInRange:NSMakeRange(0, str.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
if (![lowercaseString containsString:substring]) {
isPangram = NO;
*stop = YES;
}
}];
return isPangram;
}

@end

# Transpose

Transpose
Take input text and output it transposed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Transpose.h
#import <Foundation/Foundation.h>

@interface Transpose : NSObject

+ (NSArray *)transpose:(NSArray *)array;

@end

// Transpose.m
#import "Transpose.h"

@implementation Transpose

+ (NSArray *)transpose:(NSArray *)array {
NSInteger length = 0;
for (NSString *sunstring in array) {
length = MAX(length, sunstring.length);
}
NSMutableArray *result = [NSMutableArray array];
for (NSInteger i = 0; i < length; ++i) {
NSString *string = @"";
for (NSInteger j = 0; j < array.count; ++j) {
NSString *obj = array[j];
if (obj.length > i) {
string = [string stringByAppendingString:[obj substringWithRange:NSMakeRange(i, 1)]];
} else {
string = [string stringByAppendingString:@" "];
}
}
while ([string hasSuffix:@" "]) {
string = [string substringToIndex:string.length - 1];
}
[result addObject:string];
}
return result;
}

@end

Binary Search
Implement a binary search algorithm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// BinarySearch.h
#import <Foundation/Foundation.h>

@interface BinarySearch : NSObject

@property (nonatomic, strong) NSArray *list;
@property (nonatomic, assign) NSInteger middle;

- (instancetype)initWithArray:(NSArray *)array;
- (NSInteger)searchFor:(NSInteger)number;

@end

// BinarySearch.m
#import "BinarySearch.h"

@implementation BinarySearch

- (instancetype)initWithArray:(NSArray *)array {
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
return [obj1 integerValue] > [obj2 integerValue];
}];
if (![array isEqualToArray:sortedArray]) {
return nil;
}
if (self = [super init]) {
self.list = array;
self.middle = array.count / 2;
}
return self;
}

- (NSInteger)searchFor:(NSInteger)number {
NSInteger middle = self.list.count / 2;
NSInteger middleValue = [self.list[middle] integerValue];
NSArray *subarray = self.list;
do {
if (number == middleValue) {
return [self.list indexOfObject:subarray[middle]];
}
if (middle == 0) {
return NSNotFound;
}
if (number > middleValue) {
subarray = [subarray subarrayWithRange:NSMakeRange(middle + 1, subarray.count % 2 == 0 ? middle - 1 : middle)];
} else {
subarray = [subarray subarrayWithRange:NSMakeRange(0, middle)];
}
middle = subarray.count / 2;
middleValue = [subarray[middle] integerValue];
} while (YES);
return NSNotFound;
}

@end

# Crypto Square

Crypto Square
Implement the classic method for composing secret messages called a square code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// CryptoSquare.h
#import <Foundation/Foundation.h>

@interface CryptoSquare : NSObject

@property (nonatomic, assign) NSInteger numberOfColumns;
@property (nonatomic, strong) NSArray *plaintextSegments;
@property (nonatomic, copy) NSString *cipherText;
@property (nonatomic, copy) NSString *normalizedCipherText;
@property (nonatomic, copy) NSString *normalizePlaintext;

- (instancetype)initWithText:(NSString *)text;

@end

// CryptoSquare.m
#import "CryptoSquare.h"

@interface CryptoSquare ()

@property (nonatomic, assign) NSInteger numberOfRows;

@end

@implementation CryptoSquare

- (instancetype)initWithText:(NSString *)text {
if (self = [super init]) {
self.normalizePlaintext = [[text lowercaseString] stringByReplacingOccurrencesOfString:@"[^a-z0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, text.length)];
}
return self;
}

- (NSInteger)numberOfColumns {
for (NSInteger c = 1; c <= self.normalizePlaintext.length; ++c) {
NSInteger r = self.normalizePlaintext.length / c + (self.normalizePlaintext.length % c > 0 ? 1 : 0);
if (c >= r && c - r <= 1) {
self.numberOfRows = r;
return c;
}
}
return 0;
}

- (NSArray *)plaintextSegments {
return [self segments:self.normalizePlaintext];
}

- (NSString *)cipherText {
NSArray *array = self.plaintextSegments;
NSMutableString *result = [NSMutableString string];
for (NSInteger i = 0; i < self.numberOfColumns; ++i) {
for (NSInteger j = 0; j < array.count; ++j) {
if ([array[j] length] > i) {
[result appendString:[array[j] substringWithRange:NSMakeRange(i, 1)]];
}
}
}
return result;
}

- (NSString *)normalizedCipherText {
return [[self segments:self.cipherText] componentsJoinedByString:@" "];
}

- (NSArray *)segments:(NSString *)text {
NSInteger c, r;
if ([text isEqualToString:self.normalizePlaintext]) {
c = self.numberOfColumns;
r = self.numberOfRows;
} else {
c = self.numberOfRows;
r = self.numberOfColumns;
}
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < r; ++i) {
if (i < r - 1) {
[array addObject:[text substringWithRange:NSMakeRange(i * c, c)]];
} else {
[array addObject:[text substringFromIndex:i * c]];
}
}
return array;
}

@end