23
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swift/Kotlin愛好会Advent Calendar 2020

Day 6

競プロで使えるアルゴリズム関数一覧(Swift)

Last updated at Posted at 2020-12-05

私はSwiftにおける競プロの記事をいくつか投稿しています。

自分で武器を増やしていくのが競プロの面白さのひとつだと思っているので、まずは自分で考えるのがオススメです。
どうしてもわからないときに、私の記事が参考になると嬉しいです :relaxed:

はじめに

本記事は Swift/Kotlin愛好会 Advent Calendar 2020 の6日目の記事です。
競プロで使えるアルゴリズムの関数を紹介します。

注意

  • 本記事で紹介している関数および計算量が正しいかは保証できていません。
  • さらに計算量が小さいプログラムが存在する可能性があります。
  • 本記事は随時更新予定です。

環境

  • OS:macOS Big Sur 11.0.1
  • Xcode:12.2 (12B45b)
  • Swift:5.3.1
    5.2.1(2020/12/06現在のAtCoder)でも動作する

競プロで使えるアルゴリズム関数一覧

順列全探索

説明

TBD

ソースコード
private func permutations<T>(of values: [T]) -> [[T]] {
    if values.count <= 1 {
        return [values]
    }
    var results: [[T]] = []
    for i in values.indices {
        let baseValue = values[i]
        var excludingBaseValue = values
        excludingBaseValue.remove(at: i)
        results += permutations(of: excludingBaseValue).map { [baseValue] + $0 }
    }
    return results
}
出力例
[1, 3] -> [[1, 3], [3, 1]]
[1, 2, 4] -> [[1, 2, 4], [1, 4, 2], [2, 1, 4], [2, 4, 1], [4, 1, 2], [4, 2, 1]]
[1, 2, 3, 5] -> [[1, 2, 3, 5], [1, 2, 5, 3], [1, 3, 2, 5], [1, 3, 5, 2], [1, 5, 2, 3], [1, 5, 3, 2], [2, 1, 3, 5], [2, 1, 5, 3], [2, 3, 1, 5], [2, 3, 5, 1], [2, 5, 1, 3], [2, 5, 3, 1], [3, 1, 2, 5], [3, 1, 5, 2], [3, 2, 1, 5], [3, 2, 5, 1], [3, 5, 1, 2], [3, 5, 2, 1], [5, 1, 2, 3], [5, 1, 3, 2], [5, 2, 1, 3], [5, 2, 3, 1], [5, 3, 1, 2], [5, 3, 2, 1]]
計算量

TBD

参考リンク

TBD

階乗

説明

$n!$ を返します。

まだAtCoderでは使ったことがありません。

ソースコード
private func factorial(of value: Int) -> Int {
    precondition(value >= 0)
    if value == 0 {
        return 1
    }
    return (1...value).reduce(1, *)
}
出力例
0 -> 1
1 -> 1
2 -> 2
3 -> 6
9 -> 362880
計算量

$O(N)$

参考リンク

組み合わせ

説明

$_nC_r$ を返します。

ソースコード
private func combination(n: Int, r: Int) -> Int {
    precondition(n > 0 && r >= 0)
    if r == 0 {
        return 1
    }
    if r > n {
        return 0
    }
    var result = 1
    for i in 1...r {
        result *= n - (i - 1)
        result /= i
    }
    return result
}

$\frac{_nP_r}{r!}$ の分子から計算すると( $n$ や $r$ の大きさによっては)64 bit 整数型ではオーバーフローするため、掛けて割ってを繰り返しています。
割る数値を $1, 2, \ldots, r$ と1から昇順に増やすことで、 result は常に整数となります。

出力例
(n: 1, r: 0) -> 1
(n: 1, r: 1) -> 1
(n: 1, r: 2) -> 0
(n: 2, r: 1) -> 2
(n: 11, r: 11) -> 1
(n: 12, r: 11) -> 12
(n: 13, r: 11) -> 78
(n: 16, r: 11) -> 4368
(n: 199, r: 11) -> 366461620334848584
計算量

$O(r)$

参考リンク

約数列挙

説明

与えられた数値の約数をすべて求め、昇順に整列した配列で返します。
整列する必要がない場合、返却時の sorted() を外してください。

ソースコード
import Foundation

private func divisors(of value: Int) -> [Int] {
    precondition(value > 0)
    var divisors: Set<Int> = []
    for i in 1...(Int(floor(sqrt(Double(value))))) where value % i == 0 {
        divisors.insert(i)
        divisors.insert(value / i)
    }
    return divisors.sorted()
}

divisors 変数を通常の配列でなく Set<Int> 型で定義している理由は、数値が平方数(例: 25)の場合に約数が重複するのを防ぐためです。
通常の配列は重複を許すため 25 -> [1, 5, 5, 25] となりますが、 Set<Int> は重複を許さないので 25 -> [1, 5, 25] となります。

出力例
1 -> [1]
2 -> [1, 2]
3 -> [1, 3]
4 -> [1, 2, 4]
5 -> [1, 5]
6 -> [1, 2, 3, 6]
7 -> [1, 7]
8 -> [1, 2, 4, 8]
9 -> [1, 3, 9]
10 -> [1, 2, 5, 10]
11 -> [1, 11]
12 -> [1, 2, 3, 4, 6, 12]
13 -> [1, 13]
14 -> [1, 2, 7, 14]
15 -> [1, 3, 5, 15]
16 -> [1, 2, 4, 8, 16]
17 -> [1, 17]
18 -> [1, 2, 3, 6, 9, 18]
19 -> [1, 19]
20 -> [1, 2, 4, 5, 10, 20]
21 -> [1, 3, 7, 21]
22 -> [1, 2, 11, 22]
23 -> [1, 23]
24 -> [1, 2, 3, 4, 6, 8, 12, 24]
25 -> [1, 5, 25]
26 -> [1, 2, 13, 26]
27 -> [1, 3, 9, 27]
28 -> [1, 2, 4, 7, 14, 28]
29 -> [1, 29]
30 -> [1, 2, 3, 5, 6, 10, 15, 30]
計算量

$O(\sqrt{N})$

参考リンク

素因数分解

説明

与えられた数値を素因数分解し、昇順に整列した配列で返します。

ソースコード
import Foundation

private func primeFactorizations(of value: Int) -> [Int] {
    precondition(value > 0)
    if (1...3).contains(value) {
        return [value]
    }

    var copiedValue = value
    var primeFactorizations: [Int] = []
    for i in 2...Int(floor(Double(n) / 2)) {
        while copiedValue % i == 0 {
            copiedValue /= i
            primeFactorizations.append(i)
        }
        if primeFactorizations.reduce(1, *) == value {
            break
        }
    }
    if primeFactorizations.isEmpty {
        primeFactorizations.append(value)
    }
    return primeFactorizations
}
出力例
1 -> [1]
2 -> [2]
3 -> [3]
4 -> [2, 2]
5 -> [5]
6 -> [2, 3]
7 -> [7]
8 -> [2, 2, 2]
9 -> [3, 3]
10 -> [2, 5]
11 -> [11]
12 -> [2, 2, 3]
13 -> [13]
14 -> [2, 7]
15 -> [3, 5]
16 -> [2, 2, 2, 2]
17 -> [17]
18 -> [2, 3, 3]
19 -> [19]
20 -> [2, 2, 5]
21 -> [3, 7]
22 -> [2, 11]
23 -> [23]
24 -> [2, 2, 2, 3]
25 -> [5, 5]
26 -> [2, 13]
27 -> [3, 3, 3]
28 -> [2, 2, 7]
29 -> [29]
30 -> [2, 3, 5]
計算量

TBD

参考リンク

TBD

最大公約数

説明

$1$ 以上の整数 $a$ と $b$ の最大公約数を返します。

ソースコード
private func gcd(_ a: Int, _ b: Int) -> Int {
    precondition(a > 0 && b >= 0)
    return b == 0 ? a : gcd(b, a % b)
}
出力例
gcd(2, 3) -> 1
gcd(6, 3) -> 3
gcd(24, 36) -> 12
計算量

$O(\log{N})$

$N$ は $a$ と $b$ のうち小さいほうの数値

参考リンク

最小公倍数

TBD

おわりに

以上、 Swift/Kotlin愛好会 Advent Calendar 2020 の6日目の記事でした。
明日も @uhooi の記事です。

参考リンク

23
15
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?