Menu
Coddy logo textTech

最長継続日数

CoddyのSwiftジャーニー「ロジックとフロー」セクションの一部 — レッスン 35/56。

ストリークとは、習慣が完了としてマークされた連続した日数のことです。日付が [1, 2, 3, 5, 6] の場合、最長のストリークは 3 (1〜3日目)です。

ソート済みの日のリストがあれば、その計算は単純な線形スキャンで行えます。各日を前の日と比較し、連続している場合は現在の連続期間を延長し、そうでない場合はリセットします。

func longestStreak(_ days: [Int]) -> Int {
    let sorted = days.sorted()
    var best = 0
    var run = 0
    var prev: Int? = nil
    for d in sorted {
        if let p = prev, d == p + 1 {
            run += 1
        } else {
            run = 1
        }
        if run > best { best = run }
        prev = d
    }
    return best
}

「現在の実行を追跡する + これまでの最高」というパターンは、多くの問題で繰り返し現れます。一度認識してしまえば、それは永遠にあなたのものです。

challenge icon

チャレンジ

中級

1行の入力を読み込みます。これはカンマで区切られた habit:day のエントリのリストです。前のレッスンと同じように辞書を構築し、各習慣について、1週間を通した最長の連続日数の記録(ストリーク)を計算してください。

習慣をアルファベット順に、1行に1つずつ、以下の形式で出力してください:

<habit>: streak=<n>

入力が read:1,read:2,read:3,read:5,workout:2,workout:4 の場合、出力は以下のようになります:

read: streak=3
workout: streak=1

チートシート

最長ストリーク – 現在の連続数とこれまでの最大値を追跡する線形スキャン:

func longestStreak(_ days: [Int]) -> Int {
    let sorted = days.sorted()
    var best = 0, run = 0
    var prev: Int? = nil
    for d in sorted {
        if let p = prev, d == p + 1 { run += 1 } else { run = 1 }
        if run > best { best = run }
        prev = d
    }
    return best
}

各要素が前の要素に1を足したものと等しいとき、日数は連続しているとみなされます。隙間がある場合は run1 にリセットし、各反復(イテレーション)ごとに best を更新します。

自分で試してみよう

var habits: [String: [Int]] = [:]
let ops = readLine()!.components(separatedBy: ",")
for op in ops {
    let parts = op.components(separatedBy: ":")
    let day = Int(parts[1])!
    if !(habits[parts[0], default: []].contains(day)) {
        habits[parts[0], default: []].append(day)
    }
}

// TODO: 習慣ごとの最長継続日数を算出し、名前順に 'name: streak=n' の形式で出力する
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

ロジックとフローのすべてのレッスン