Open3

Codewars 演習記録 in Rust

えとあるえとある

<7 kyu> Waiting room

題意要約:

ある待合室には 1 から n までの番号が振られた n 脚の椅子が置かれていて、利用者は以下のルールに従って順番に席に座っていく。

  • 既に座っている人からなるべく距離(間隔)の空いた椅子に座る
  • 他の人との間隔が同じ席が複数ある場合、その中で入り口に近い(=番号の若い)椅子に座る

椅子の数 n (> 2) を引数として、この待合室が満席となるときに最後に埋まる席番号を返す関数 last_chair を実装せよ。

7 kyu のくせに 序盤から結構難しいんですけど……(;'-' )

思索1

椅子を模して長さ nVec<u32> を用意して、空席を 0、座られている席を 1 とし、ベクタの中で一番 0 が連続するスライスから次に埋まる席を順に求めていくか…?

思索2

埋まっている席を考えるより、隙間の大きさを考えていったほうが良さそうだな。つまり席数 n = 10 の場合を例に考えると、条件: n > 2 より 1人目は必ず番号1、2人目は必ず番号10の椅子に座るので2人の間隔は 10 - 1 = 9 となる。3人目は間隔 9 のうちの真ん中の席に座るので、1 + (9 / 2) as u32 で番号5 の椅子。以下同様に、間隔の系列の最大値を整数 2 で割ることを繰り返す。これを

  • [9]
  • [4, 5]
  • [4, 2, 3]
  • [2, 2, 2, 3]
  • ...

のように「間隔の系列」を要素とするベクタに持たせて、in-place で更新していったときに最後に 2 → 1 になる要素のインデックス + 1 が最後に埋まる席番号だ!

思索3

↑...とかなんか面倒くさいこと考えなくても、今って最後に埋まる席番号さえ分かればいいんじゃん。ってことは…

解答例

思索2の処理をそのまま続けていくと、最後は1つ飛ばし(=間隔 2)で空いた席の中で必ず番号が若い順に埋まっていく状況になるので、最後に埋まるのは最後尾から2番目 = 席数 n より 1 小さい席番号となる。

fn last_chair(n: u32) -> u32 {
    n - 1
}
えとあるえとある

<7 kyu> Disemvowel Trolls

トロールたちがお前のサイトのコメント欄に悪口を書き込んでいるぞ! やつらのコメントから母音字(小文字/大文字含む)を削除して、何を言っているか分からなくしてやれ! 与えられた文字列から母音字のみを削除した文字列を返す関数 disemvowel を実装せよ。ただし y は母音字の対象外とする。

Rust を学習しはじめた2年前の解答と、現在の私ならこう書くかな(シュッと解けた…よかった😌)という解答を置いておきます。

解答例1(Rustを学び始めたばかりの頃の私の解答)
  • 文字型 Char はダブルクォーテーション "" ではなくシングルクォーテーション '' で囲むのか!
  • 文字型が母音字かどうかをチェックする…これはパターンマッチングの使いどころだ!

などということを考えながら書いた記憶があります。かわいいですね☺️

fn disemvowel(s: &str) -> String {
    let mut stack = vec![];
    
    for c in s.chars() {
        match c {
            'a' | 'e' | 'i' | 'o' | 'u' | 'A' | 'E' | 'I' | 'O' | 'U' => continue,
            _ => stack.push(c),
        };
    };
    
    let answer: String = stack.into_iter().collect();
    
    answer
}
解答例2(↑から2年後の私の解答)

今ならワンライナーでシュッと書きます。 filter 関数の格好の出番です。filter のクロージャ内での母音字の列挙は !"aeiou".contains(c.to_lower_ascii()) でも良いでしょう。

fn disemvowel(s: &str) -> String {
    s.chars().filter(|&c| !"AEIOUaeiou".contains(c)).collect()
}