このページについて
このページは、paiza ラーニング内に開設されているコンテンツ「レベルアップ問題集」で取り扱われているプログラミング課題について、独自の見解を述べたものです。
見解については、paizaラーニングの規約に基づき、許可されている範囲でのみ公開していますが、その内容については paiza とは一切関係なく、また paiza の立場を反映したものではありませんのでご注意ください。
挑戦する課題
レベルアップ問題集の日付セットから「最長の連休paiza (paizaランク C 相当)」を取り上げます。
以下は、問題公開 Web ページからの引用です。
問題
西暦2019年の最長となる連休の日数を求めてください。
ただし、paiza国のカレンダーに即して計算しなければならないことに注意してください。
連休とは、連続する休業日のことです。
paiza国のカレンダーでの休業日とは、土曜日、日曜日、または、祝日のことです。
祝日は、入力データとして与えらます。
また、祝日が土曜日・日曜日と重複したとしても振り替えられることはありません。
西暦2019年1月1日は火曜日です。
入力される値
以下の形式で、整数Nが1行目で与えられ、続くN行で西暦2019年のpaiza暦の祝日の一覧が与えらます。
1 2 3 4 5 |
N M_1 D_2 M_2 D_3 ... M_N D_N |
- 西暦2019年M_i月D_i日(1 ≦ i ≦ N)はpaiza暦の祝日です。
期待する出力
以下のような形式で、答えを出力してください。
1 |
d |
- dは答えの日数です。
入出力例
- 入力例1
1 2 3 |
2 8 13 10 31 |
- 出力例1
1 |
2 |
考え方
ごく基本的な考え方は、1月1日を木曜日として曜日の計算を行い、土日にチェックをつけてゆく方法を採用するのが一番簡単だと思われます。
おそらく、もっと効率的な考え方があるかと思いますが、まずは愚直な方法で解いてみたいと思います。
たとえば、祝日は "x", 平日は "o" とすれば、
1 |
xoooooxxoxooxxx..... |
のような感じで365日記録し、そのうち連続した xの数を数えるという方法です。
ただし、今回の問題では「paiza祝日」が決められているので、ある日が祝日であれば、その部分も x にしなければなりません。
祝日の形式は、たとえば8月13日が祝日ということであれば
1 |
8 13 |
という形式で与えられますので、これをなんらかの方法で管理する必要があります。
今回も辞書(
Dictionary)を使い、
key に月数、
value に休みの日を代入し、記録することにしました。
ただし、休みの日については、1つの月で複数日あることもあるため、
[Int: [Int]] という具合に、
value については
Int 型の配列とし、そこに休みの日付を追加することにします。
これを、1月1日から12月31日まで逐次チェックし、記録をつけてゆきます。
最終的には、先にも述べたように "xoooooxxoxo....." のような文字列となって一年分のデータが記録されますから、これを基に最長となる連休を求める必要があります。
ここでは、記録した一年分のデータを
split(separator:)を使って区切り、
["x", "xx", "x", ...] のような配列へと変換します。
その後、一つひとつの要素について文字列長を求め、それが一番長いものが、最大の連休数となるように求めてみました。
解答例
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 |
// 入力行数。無視して構わない _ = readLine() // 休日を管理する辞書。[月:[休日の配列]] var ha = [Int: [Int]]() // 辞書内の配列を初期化 for i in 1...12 { ha[i] = [] } // 祝日定義を最終行まで読み込む let ia = Array(AnyIterator { readLine() }).map{ $0.split(separator: " ").map { Int($0)! } } // 月別の休日を配列に追加する for i in ia { ha[i[0]]!.append(i[1]) } // 月と日付 var m = 1 var d = 1 // 年間の通し日数 var yd = 1 // 365 日の日祝日フラグ var hd = "" repeat { // 曜日を求める。w == 1 のとき火曜日 let w = yd % 7 // あらかじめ入力された休日データに、当日が含まれるか、あるいはその日が土曜もしくは日曜か判断 if ha[m]!.contains(d) || w == 5 || w == 6 { hd += "x" } else { hd += " " } d += 1 yd += 1 // 月跨ぎ処理 switch m { case 4, 6, 9, 11: if d == 31 { m += 1 d = 1 } case 2: if d == 29 { m += 1 d = 1 } default: if d == 32 { m += 1 d = 1 } } } while m < 13 // 最大の連級数 var max = 0 // 365日分の日祝日データが空白区切り(平日が空白)で入っているので、空白を区切りとして分割する for dd in hd.split(separator: " ") { // "x"の数を数え、最大血であれば更新 if dd.count > max { max = dd.count } } // 再長の連休数を出力 print(max) |