Skip to content

Commit d55a224

Browse files
authored
Merge pull request kodecocodes#270 from JaapWijnen/migrate-combinatorics-swift3
migrate combinatorics to swift3
2 parents 2924e18 + 2b64b05 commit d55a224

File tree

4 files changed

+40
-155
lines changed

4 files changed

+40
-155
lines changed

Combinatorics/Combinatorics.playground/Contents.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//: Playground - noun: a place where people can play
22

33
/* Calculates n! */
4-
func factorial(n: Int) -> Int {
4+
func factorial(_ n: Int) -> Int {
55
var n = n
66
var result = 1
77
while n > 1 {
@@ -20,7 +20,7 @@ factorial(20)
2020
Calculates P(n, k), the number of permutations of n distinct symbols
2121
in groups of size k.
2222
*/
23-
func permutations(n: Int, _ k: Int) -> Int {
23+
func permutations(_ n: Int, _ k: Int) -> Int {
2424
var n = n
2525
var answer = n
2626
for _ in 1..<k {
@@ -41,7 +41,7 @@ permutations(9, 4)
4141
Original algorithm by Niklaus Wirth.
4242
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
4343
*/
44-
func permuteWirth<T>(a: [T], _ n: Int) {
44+
func permuteWirth<T>(_ a: [T], _ n: Int) {
4545
if n == 0 {
4646
print(a) // display the current permutation
4747
} else {
@@ -75,7 +75,7 @@ permuteWirth(xyz, 2)
7575
Original algorithm by Robert Sedgewick.
7676
See also Dr.Dobb's Magazine June 1993, Algorithm Alley
7777
*/
78-
func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) {
78+
func permuteSedgewick(_ a: [Int], _ n: Int, _ pos: inout Int) {
7979
var a = a
8080
pos += 1
8181
a[n] = pos
@@ -103,16 +103,16 @@ permuteSedgewick(numbers, 0, &pos)
103103
Calculates C(n, k), or "n-choose-k", i.e. how many different selections
104104
of size k out of a total number of distinct elements (n) you can make.
105105
*/
106-
func combinations(n: Int, _ k: Int) -> Int {
106+
func combinations(_ n: Int, choose k: Int) -> Int {
107107
return permutations(n, k) / factorial(k)
108108
}
109109

110-
combinations(3, 2)
111-
combinations(28, 5)
110+
combinations(3, choose: 2)
111+
combinations(28, choose: 5)
112112

113113
print("\nCombinations:")
114114
for i in 1...20 {
115-
print("\(20)-choose-\(i) = \(combinations(20, i))")
115+
print("\(20)-choose-\(i) = \(combinations(20, choose: i))")
116116
}
117117

118118

@@ -121,7 +121,7 @@ for i in 1...20 {
121121
Calculates C(n, k), or "n-choose-k", i.e. the number of ways to choose
122122
k things out of n possibilities.
123123
*/
124-
func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
124+
func quickBinomialCoefficient(_ n: Int, choose k: Int) -> Int {
125125
var result = 1
126126

127127
for i in 0..<k {
@@ -131,8 +131,8 @@ func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
131131
return result
132132
}
133133

134-
quickBinomialCoefficient(8, 2)
135-
quickBinomialCoefficient(30, 15)
134+
quickBinomialCoefficient(8, choose: 2)
135+
quickBinomialCoefficient(30, choose: 15)
136136

137137

138138

@@ -145,7 +145,7 @@ struct Array2D<T> {
145145
init(columns: Int, rows: Int, initialValue: T) {
146146
self.columns = columns
147147
self.rows = rows
148-
array = .init(count: rows*columns, repeatedValue: initialValue)
148+
array = Array(repeating: initialValue, count: rows*columns)
149149
}
150150

151151
subscript(column: Int, row: Int) -> T {
@@ -163,8 +163,8 @@ struct Array2D<T> {
163163
space for the cached values.
164164
*/
165165

166-
func binomialCoefficient(n: Int, _ k: Int) -> Int {
167-
var bc = Array(count: n + 1, repeatedValue: Array(count: n + 1, repeatedValue: 0))
166+
func binomialCoefficient(_ n: Int, choose k: Int) -> Int {
167+
var bc = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1)
168168

169169
for i in 0...n {
170170
bc[i][0] = 1
@@ -182,5 +182,5 @@ func binomialCoefficient(n: Int, _ k: Int) -> Int {
182182
return bc[n][k]
183183
}
184184

185-
binomialCoefficient(30, 15)
186-
binomialCoefficient(66, 33)
185+
binomialCoefficient(30, choose: 15)
186+
binomialCoefficient(66, choose: 33)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>

Combinatorics/Combinatorics.swift

Lines changed: 0 additions & 121 deletions
This file was deleted.

Combinatorics/README.markdown

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
A *permutation* is a certain arrangement of the objects from a collection. For example, if we have the first five letters from the alphabet, then this is a permutation:
44

55
a, b, c, d, e
6-
6+
77
This is another permutation:
88

99
b, e, d, a, c
@@ -28,7 +28,7 @@ After picking the second letter, there are only three letters left to choose fro
2828
To calculate the factorial in Swift:
2929

3030
```swift
31-
func factorial(n: Int) -> Int {
31+
func factorial(_ n: Int) -> Int {
3232
var n = n
3333
var result = 1
3434
while n > 1 {
@@ -62,7 +62,7 @@ You could implement this in terms of the `factorial()` function from earlier, bu
6262
Here is an algorithm that can deal with larger numbers:
6363

6464
```swift
65-
func permutations(n: Int, _ k: Int) -> Int {
65+
func permutations(_ n: Int, _ k: Int) -> Int {
6666
var n = n
6767
var answer = n
6868
for _ in 1..<k {
@@ -98,7 +98,7 @@ So far we've counted how many permutations exist for a given collection, but how
9898
Here's a recursive algorithm by Niklaus Wirth:
9999

100100
```swift
101-
func permuteWirth<T>(a: [T], _ n: Int) {
101+
func permuteWirth<T>(_ a: [T], _ n: Int) {
102102
if n == 0 {
103103
print(a) // display the current permutation
104104
} else {
@@ -216,7 +216,7 @@ If the above is still not entirely clear, then I suggest you give it a go in the
216216
For fun, here is an alternative algorithm, by Robert Sedgewick:
217217

218218
```swift
219-
func permuteSedgewick(a: [Int], _ n: Int, inout _ pos: Int) {
219+
func permuteSedgewick(_ a: [Int], _ n: Int, _ pos: inout Int) {
220220
var a = a
221221
pos += 1
222222
a[n] = pos
@@ -282,7 +282,7 @@ The formula for `C(n, k)` is:
282282

283283
As you can see, you can derive it from the formula for `P(n, k)`. There are always more permutations than combinations. You divide the number of permutations by `k!` because a total of `k!` of these permutations give the same combination.
284284

285-
Above I showed that the number of permutations of `k` `l` `m` is 6, but if you pick only two of those letters the number of combinations is 3. If we use the formula we should get the same answer. We want to calculate `C(3, 2)` because we choose 2 letters out of a collection of 3.
285+
Above I showed that the number of permutations of `k` `l` `m` is 6, but if you pick only two of those letters the number of combinations is 3. If we use the formula we should get the same answer. We want to calculate `C(3, 2)` because we choose 2 letters out of a collection of 3.
286286

287287
3 * 2 * 1 6
288288
C(3, 2) = --------- = --- = 3
@@ -291,15 +291,15 @@ Above I showed that the number of permutations of `k` `l` `m` is 6, but if you p
291291
Here's a simple function to calculate `C(n, k)`:
292292

293293
```swift
294-
func combinations(n: Int, _ k: Int) -> Int {
294+
func combinations(_ n: Int, choose k: Int) -> Int {
295295
return permutations(n, k) / factorial(k)
296296
}
297297
```
298298

299299
Use it like this:
300300

301301
```swift
302-
combinations(28, 5) // prints 98280
302+
combinations(28, choose: 5) // prints 98280
303303
```
304304

305305
Because this uses the `permutations()` and `factorial()` functions under the hood, you're still limited by how large these numbers can get. For example, `combinations(30, 15)` is "only" `155,117,520` but because the intermediate results don't fit into a 64-bit integer, you can't calculate it with the given function.
@@ -319,7 +319,7 @@ After the reduction of fractions, we get the following formula:
319319
We can implement this formula as follows:
320320

321321
```swift
322-
func quickBinomialCoefficient(n: Int, _ k: Int) -> Int {
322+
func quickBinomialCoefficient(_ n: Int, choose k: Int) -> Int {
323323
var result = 1
324324
for i in 0..<k {
325325
result *= (n - i)
@@ -334,8 +334,8 @@ This algorithm can create larger numbers than the previous method. Instead of ca
334334
Here's how you can use this improved algorithm:
335335

336336
```swift
337-
quickBinomialCoefficient(8, 2) // prints 28
338-
quickBinomialCoefficient(30, 15) // prints 155117520
337+
quickBinomialCoefficient(8, choose: 2) // prints 28
338+
quickBinomialCoefficient(30, choose: 15) // prints 155117520
339339
```
340340

341341
This new method is quite fast but you're still limited in how large the numbers can get. You can calculate `C(30, 15)` without any problems, but something like `C(66, 33)` will still cause integer overflow in the numerator.
@@ -345,10 +345,10 @@ Here is an algorithm that uses dynamic programming to overcome the need for calc
345345
0: 1
346346
1: 1 1
347347
2: 1 2 1
348-
3: 1 3 3 1
349-
4: 1 4 6 4 1
350-
5: 1 5 10 10 5 1
351-
6: 1 6 15 20 15 6 1
348+
3: 1 3 3 1
349+
4: 1 4 6 4 1
350+
5: 1 5 10 10 5 1
351+
6: 1 6 15 20 15 6 1
352352

353353
Each number in the next row is made up by adding two numbers from the previous row. For example in row 6, the number 15 is made by adding the 5 and 10 from row 5. These numbers are called the binomial coefficients and as it happens they are the same as `C(n, k)`.
354354

@@ -365,8 +365,8 @@ For example, for row 6:
365365
The following code calculates Pascal's triangle in order to find the `C(n, k)` you're looking for:
366366

367367
```swift
368-
func binomialCoefficient(n: Int, _ k: Int) -> Int {
369-
var bc = Array(count: n + 1, repeatedValue: Array(count: n + 1, repeatedValue: 0))
368+
func binomialCoefficient(_ n: Int, choose k: Int) -> Int {
369+
var bc = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1)
370370

371371
for i in 0...n {
372372
bc[i][0] = 1
@@ -390,7 +390,7 @@ The algorithm itself is quite simple: the first loop fills in the 1s at the oute
390390
Now you can calculate `C(66, 33)` without any problems:
391391

392392
```swift
393-
binomialCoefficient(66, 33) // prints a very large number
393+
binomialCoefficient(66, choose: 33) // prints a very large number
394394
```
395395

396396
You may wonder what the point is in calculating these permutations and combinations, but many algorithm problems are really combinatorics problems in disguise. Often you may need to look at all possible combinations of your data to see which one gives the right solution. If that means you need to search through `n!` potential solutions, you may want to consider a different approach -- as you've seen, these numbers become huge very quickly!

0 commit comments

Comments
 (0)