最長継続日数
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
}「現在の実行を追跡する + これまでの最高」というパターンは、多くの問題で繰り返し現れます。一度認識してしまえば、それは永遠にあなたのものです。
チャレンジ
中級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を足したものと等しいとき、日数は連続しているとみなされます。隙間がある場合は run を 1 にリセットし、各反復(イテレーション)ごとに 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' の形式で出力する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。