🕌

AtCoder Begibbers Selection ABC049C - 白昼夢 備忘録

2024/03/01に公開

ABC049C - 白昼夢

問題はこちら
AtCoder Beginner Selection ABC049C - 白昼夢

解答

<?php
$s = trim(fgets(STDIN));

// 使用できる文字列
$wards = ["dream", "dreamer", "erase", "eraser"];


while(strlen($s) > 0){
  $matched = false;
  foreach($wards as $word){
    // sの末尾がwordで終わっているかのチェック
    if(substr($s, -strlen($word)) == $word){
    //  一致するならsからその部分を削除
    $s = substr($s, 0, -strlen($word));
    $matched = true;
    break;
    }
  }
  // どの単語も一致しなければ終了
  if(!$matched){
    break;
  }
  
}


echo (strlen($s) == 0) ? "YES\n" : "NO\n";

つまづきポイント

  • 照合する回数が決まっているためwhileを使うという発想は出たがやり方が出てこなかった
  • 末尾のみ違う単語があるため、先頭の文字列から照合していくと結論に違いが出てくる考えはまったく気づかなかった
  • 標準入力から単語を削除していく発想は出たがやり方がわからなかった

考察とポイント

文字列(string)の先頭からN文字を削除するには、2つの引数を使います。
まず、substr()を呼び出します。
そして、substr()の第1引数に対象の文字列、第2引数に削除する文字数を指定します。

//text=対象の文字列, n=削除する文字数
$result = substr(text, n);

今回は最後尾から文字数をカウントして削除するため-(マイナス)を使っています。
また文字数は要素によって違うため、配列と変数を使用して文字数を指定しています。

// $sは文字列、$wordは文字列の変数
$s = substr($s, 0, -strlen($word));

offset指定による違い

// $sは文字列、$wordは文字列の変数
$s = substr($s, 0, -strlen($word));

// $sは文字列、$wordは文字列の変数
$s = substr($s, -strlen($word));

の違い

substr(string string, int $start, ?int $length = null): ここで、stringは処理される文字列、startは切り出しを開始する位置、lengthは切り出す長さです。
substr(s, 0, -strlen(word)): ここでは、文字列の最初(位置0)から始まり、末尾から$wordの長さ分だけ前の位置までの部分文字列を返します。

substr(s, -strlen(word)): この場合、startは負の数として扱われ、文字列の末尾から数えてwordの長さ分の位置から切り出しを始めます。結果として、これは文字列の末尾の$wordの長さ分の部分だけを返します。

つまり、これらの呼び出しは異なる結果をもたらします:

substr(s, 0, -strlen(word))は文字列の先頭から始まり、末尾の$wordの長さ分だけ前の位置までの部分を返します。
substr(s, -strlen(word))は文字列の末尾から$wordの長さ分だけの部分を返します。
これらの違いは、文字列のどの部分を取り出すかという点で重要です。最初のコードは文字列の末專からwordの長さを取り除くのに対し、二番目のコードは文字列の末尾からwordの長さ分の部分を取り出します。

参考になるページ

公式ドキュメント substr
[PHP]substr()で文字列の先頭からN文字を削除するには?

Discussion