【Ruby基礎】AtCoder Beginner Contest 032 B - 高橋君とパスワード

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 032のB問題 https://atcoder.jp/contests/abc032/tasks/abc032_b

●問題文

高橋君の会社には、秘密の金庫があります。この金庫にはパスワードをかけているのですが、高橋君はそのパスワードを忘れてしまいました。 しかし、幸運なことに、手元にはパスワードのヒントが以下のように書かれていました。

  • パスワードは、この紙に書かれている文字列 s の長さ k の部分文字列(※)のどれかである。

高橋君は、ありうるパスワードを全部試せば金庫を開けられる!と喜びました。 しかし、文字列 s はとても長い可能性があるし、しかも同じ部分文字列が複数個文字列 s 中に存在する可能性もあります。明らかに、重複したパスワードを繰り返し試す必要はありません。 そこで、手動で全てのパスワードを試す前に、試す必要がある異なるパスワードの数がいくつあるかを数えることにしました。

あなたの仕事は、文字列 s の内容が与えられるので、試す必要がある異なるパスワードの数がいくつあるかを高橋君に教えてあげることです。

(※)文字列 s の「部分文字列」とは、文字列 s に含まれるある区間を取り出した文字列のことです。 例えば、abc の部分文字列として a,b,c,ab,bc,abc などが挙げられます。 acba などは部分文字列ではないことに注意してください。

●入力

入力は以下の形式で標準入力から与えられる。

s
k
  • 1 行目には、ヒントの紙に書かれている文字列 s(1≦∣s∣≦300) が与えられる。s は英小文字(a-z)のみから成る。∣s∣ は文字列 s の長さを表す。
  • 2 行目には、パスワードとしてありうる整数 k(1≦k≦300) が与えられる。 k は ∣s∣ よりも大きいことがある。

●出力

出力は以下の形式で標準出力に行うこと。 1 行目に、パスワードとして考えられる文字列の数を出力せよ。末尾の改行を忘れないこと。

■回答

●愚直に書く

これは苦手なやつだ…。

標準入力としては1行目の文字列を取り、2行目の整数を取る。

その後にループ処理の中で文字列の中から必要な文字数分だけ順番に要素を取り出してそれを配列に入れていき、最後に重複を省いてカウントすれば良さそう。

と、文字で書くのは良いとしてどうやってコードに落とし込むか…。

(下記に至るまでかなりの試行錯誤があった)

ループの回数は何回だろう?初めの例から考えると、 abcabcで6文字あってその中で2文字の部分文字列を取り出すから、愚直に数え上げると['ab', 'bc', 'ca', 'ab', 'bc']を取り出す。つまり5個取り出す。 全部で6文字ある中から5個取り出す →全部の文字数 - 部分文字列の文字数 + 1、という感じか。

文字列の中から、n番目からl文字取り出すにはどうすればいいんだろう? るりまによると、self[nth, len]nth 文字目から長さ len 文字の部分文字列を新しく作って返します。とのこと。

str = gets.chomp
l = gets.to_i

array = []
(str.length - l + 1).times do |i|
  array << str[i, l]
end

puts array.uniq.size

通った!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。 今日は割愛。

リファクタリング/別アプローチ

これも今日は割愛。 他の方の回答例から学ぶアプローチにする。

●他の方の回答例

上位の方々の回答をざっと眺めた。 ポイントは以下の2つ。

  • .cahrsで文字列を配列に分解する
  • each_consで配列の要素を重複ありで区切っていき、to_aで新しく配列にまとめる

なるほど〜。

整理した回答がこちら。

str = gets.chomp.chars
l = gets.to_i

puts str.each_cons(l).to_a.uniq.size

これで通ることを確認できた。

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

今日は難しかったけど、まずはこれくらいの難易度をモタつかずに解けるようになりたい。

【Ruby基礎】AtCoder Beginner Contest 031 B - 運動管理

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 031のB問題 https://atcoder.jp/contests/abc031/tasks/abc031_b

●問題文

高橋君は AtCoder 社のマスコットキャラクターである。

マスコットキャラクターとしての魅力を維持するために、高橋君は適度な運動をすることになっている。高橋君は週の運動時間が L 分以上 H 分以下でなければならない。

しかしながら、青木君は最近、高橋君が運動しているところを見ていない。高橋君の運動状況が気になった青木君は、高橋君の過去 N 週間の運動時間が制限にあっているのか、そして足りないなら少なくともあと何分運動する必要があったのかを計算するプログラムを作成することにした。

●制約

  • ああああ

●入力

入力は以下の形式で標準入力から与えられる。

L H
N
A1
A2
:
AN
  • 1 行目には、2 個の整数 L, H(1≦L≦H≦10^4 ) が空白区切りで与えられる。これは、高橋君が週に L 分以上 H 分以下の運動をしなければならないことを表す。
  • 2 行目には、整数 N(1≦N≦50) が与えられる。これは青木君が N 週分の運動時間について調べていることを表す。
  • 3 行目からの N 行には、高橋君の運動状況を表す整数が与えられる。N 行の内 i(1≦i≦N) 行目には、整数 Ai (0≦Ai ≦10^4 ) が与えられる。これは i 個前の週において高橋君が Ai 分運動したことを表す。

●出力

出力は N 行からなる。i(1≦i≦N) 行目には、i 個前の週において高橋君が必要な分よりも多く運動している場合は −1 を、そうでない場合は追加で必要な運動時間の最小値を分単位で 1 行に出力せよ。 出力の末尾にも改行を入れること。

■回答

●愚直に書く

久しぶりのB問題。 まずは標準入力をちゃんと取るところから。

l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
  line = gets.to_i
end

# 以下は確認用
p l, h
p n
p a

これで標準入力は取れた。

次に、配列aの各要素がl以上h以下かどうかを判定していく感じか。

l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
  line = gets.to_i
end

a.each do |elm|
  if elm < l
    puts l - elm
  elsif elm > h
    puts -1
  else
    puts 0
  end
end

通った!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

メインメソッド、判定用メソッド、標準入力を取るメソッド2つの計4つ。 メインメソッド内のeachを回す部分をさらに別メソッドに分けても良いかな?

def main
  l, h = read_target
  a = read_record
  a.each do |elm|
    puts judge(l, h, elm)
  end
end

def judge(l, h, elm)
  if elm < l
    l - elm
  elsif elm > h
    -1
  else
    0
  end
end

def read_target
  gets.split.map(&:to_i)
end

def read_record
  n = gets.to_i
  n.times.map do |line|
    line = gets.to_i
  end
end

main

通った!

リファクタリング/別アプローチ

色々試したけど上手く整理できなかったので割愛…!

●他の方の回答例

maxを使った解答があり、なるほどと思った。

自分の回答に取り入れると以下のような感じ。

l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
  line = gets.to_i
end

a.each do |elm|
  if elm <= h
    puts [l - elm, 0].max
  else
    puts -1
  end
end

これだとif内がシンプルになるしそれによって三項演算子にもしやすい。なるほど。

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

計算するのにちょっと混乱してしまった。 とはいえB問題を愚直にでも解けたので良かった。

【Ruby基礎】AtCoder Beginner Contest 079 A - Good Integer

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 079のA問題 https://atcoder.jp/contests/abc079/tasks/abc079_a

●問題文

1118 のような、3 つ以上の同じ数字が連続して並んだ 4 桁の整数を 良い整数 とします。 4 桁の整数 N が与えられるので、N が 良い整数 かどうかを答えてください。

●制約

  • 1000≦N≦9999
  • 入力は整数からなる

●入力

入力は以下の形式で標準入力から与えられる。

N

●出力

N が 良い整数 ならば Yes を、そうでなければ No を出力せよ。

■回答

●愚直に書く

えーと、1つずつ配列に入れて、要素が重複してたらまとめるようなメソッドがあった気がするのでそれをやって、まとめた後の要素数が1か2であれば大丈夫か? いや、それだと1122みたいな時もまとめた後の要素数が2になるからダメだな。。。

うーん、愚直に考えて、まず配列の要素をsortして、1番目と2番目と3番目が等しければYesってことで良いか…?

やってみよう。

n = gets.chomp.split("").map(&:to_i).sort
if n[0] == n[1] && n[0] == n[2]
  puts "Yes"
else
  puts "No"
end

通った! もうちょっとスマートな方法はありそう…!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

今日は割愛。

リファクタリング/別アプローチ

絶対もっとシンプルにできそう、、、

やたら試行錯誤してしまったが、sortしているので、「1番目と2番目と3番目が等しければ」ではなく1番目と3番目が等しければ」だけで今回の条件は満たせそう。

n = gets.chomp.split("").map(&:to_i).sort
if n[0] == n[2]
  puts "Yes"
else
  puts"No"
end

通った!

三項演算子にして、

n = gets.chomp.split("").map(&:to_i).sort
puts n[0] == n[2] ? "Yes" : "No"

通った!

●他の方の回答例

アッ、正規表現…! そうか正規表現でできたのか〜。 ただ、回答例を見てもどういう書き方になっているかよく掴めていない…。

puts gets[/(.)\1\1/]?:Yes: :No

/(.)\1\1/、特に\1がわからなかったのでChatGPTさんに聞いた。

なるほど、/(.)\1\1/は同じ文字が3回連続ということか。

あと以下の回答もあって、これは力技だけどわかりやすい…!

puts gets=~/111|222|333|444|555|666|777|888|999|000/ ? "Yes" : "No"

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

正規表現を思いつけず悔しかった。 あと正規表現の理解が浅く、もうちょっと勉強せねばと思った。

【Ruby基礎】AtCoder Beginner Contest 078 A - HEX

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 078のA問題 https://atcoder.jp/contests/abc078/tasks/abc078_a

●問題文

プログラミングでは 16 進数がよく使われます。 16 進数では 0,1,...,9 の数字の他に A, B, C, D, E, F の 6 つのアルファベットを使い,それぞれ 10,11,12,13,14,15 を表します。 この問題では 2 つのアルファベット X,Y が与えられます。 X と Y はどちらも A, B, C, D, E, F のうちどれかです。 X と Y を 16 進数として見たとき,どちらのほうが大きいかを判定してください。

●制約

  • X,Y は A, B, C, D, E, F のうちどれかである。

●入力

入力は以下の形式で標準入力から与えられる。

X 
Y

●出力

X のほうが小さいならば <, Y のほうが小さいならば >, 等しいならば = と出力してください。

■回答

●愚直に書く

問題がややこしいけど、要はABCDEFの中から2文字がチョイスされてそれを比較すれば良さそう。

a, b = gets.split
if a > b
  puts ">"
elsif a < b
  puts "<"
else
  puts "="
end

通った!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。 久しぶりなのでやってみるか…!

メインメソッド、大小記号を判定するメソッド、標準入力を取得するメソッドの3つを作成。 久しぶりすぎて忘れていたので過去投稿も参考にしつつ作成した。

def main
  a, b = read_str
  puts judge(a, b)
end

def judge(a, b)
  if a > b
    ">"
  elsif a < b
    "<"
  else
    "="
  end
end

def read_str
  gets.split
end

main

通った!

リファクタリング/別アプローチ

if文のところもうちょっとスッキリできそうな気がするけど思いつかないなぁ。 なんとなく宇宙船演算子<=>)が活かせそうな気がするんだけどうまく落とし込めない。

と思いながら過去の自分の投稿で宇宙船演算子が出てきたものを見返していたら思いついた!

a, b = gets.split
puts "=><"[a <=> b]

通った〜〜〜うれしい!!

ちなみに参照した過去記事はこちら https://sugie.co/2022/11/22/ruby-abc071a/

今回でいうと、a <=> bを評価した時に-101が返って来るので、=><という文字列のインデックス部分に[a <=> b]を入れることで下記のようになる。

  • aがbより手前の文字→宇宙船演算子-1が返る→puts "=><"[-1]なので<が出力
  • aがbと同じ文字→宇宙船演算子0が返る→puts "=><"[0]なので=が出力
  • aがbより後の文字→宇宙船演算子1が返る→puts "=><"[1]なので>が出力

●他の方の回答例

上位層はほとんど宇宙船演算子を使っていた。 三項演算子入れ子を使っている人もチラホラ。

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

久しぶりにAtCoderできて楽しかった。 宇宙船演算子を使えて嬉しかった。

【GitHub】リモートmainブランチの最新状態をローカルの作業用ブランチに取り込む

自分用のメモ。

  1. git switch mainで一旦mainブランチに移動
  2. git pullでリモートのmainを取り込む
  3. git switch branch1で作業用ブランチに移動
  4. git merge mainでmainの最新状態作業用ブランチに取り込む

【Ruby基礎】AtCoder Beginner Contest 077 A - Rotation

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 077のA問題 https://atcoder.jp/contests/abc077/tasks/abc077_a

●問題文

縦 2 マス、横 3 マスのマス目が与えられます。上から i 行目、左から j 行目のマスの色は、Cij で表されます。 このマス目を180度回転させたとき、元のマス目と一致するなら YES を、そうでないなら NO を出力するプログラムを作成してください。

●制約

  • Cij (1≤i≤2,1≤j≤3) は英小文字である。

●入力

入力は以下の形式で標準入力から与えられる。

C11 C12 C13
C21 C22 C23

●出力

マス目を180度回転させたとき、元のマス目と一致するなら YES を、そうでないなら NO を出力せよ。

■回答

●愚直に書く

2行目をreverse して1行目と一致すればYESってことかな。

a = gets.chomp
b = gets.chomp
puts a.reverse == b ? 'YES' : 'NO'

通った!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

久しぶりに書くか。 2行の標準入力取得をメソッド内で書くのはどうやるんだっけ、、、

def main
  a, b = read_lines
  puts rorate?(a, b)
end

def rorate?(a, b)
  a.reverse == b ? 'YES' : 'NO'
end

def read_lines
  2.times.map do |line|
    line = gets.chomp
  end
end

main

通った!

リファクタリング/別アプローチ

リファクタリングは今日は無し。

●他の方の回答例

基本的に皆さん同じアプローチのようだった。

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

メソッド化をサボっていたのでかなり忘れていたが、久しぶりに書けてよかった。

【Ruby基礎】AtCoder Beginner Contest 076 A - Rating Goal

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。

■問題

●出典

AtCoder Beginner Contest 076のA問題 https://atcoder.jp/contests/abc076/tasks/abc076_a

●問題文

高橋君はあるプログラミングコンテストが行われているサイトに参加しています。 ここでは, コンテストに出場した時にこの順位に応じて「パフォーマンス」というものがつき、それによってレーティング (整数とは限らない) が次のように変化します。

  • 現在のレーティングを a とする。
  • 次のコンテストで, パフォーマンス b を取ったとする。
  • そのとき, レーティングは a と b の平均まで変化する。

例えば, レーティングが 1 の人が次のコンテストでパフォーマンス 1000 を取ったら, レーティングは 1 と 1000 の平均である 500.5 になります。

高橋君は, 現在のレーティングが R で, 次のコンテストでレーティングをちょうど G にしたいと思っています。 そのとき, 高橋君が取るべきパフォーマンスを求めなさい。

●制約

  • 0 ≤ R,G ≤ 4500
  • 入力はすべて整数

●入力

入力は以下の形式で標準入力から与えられる。

R
G

●出力

高橋君が取るべきパフォーマンスを出力しなさい。

■回答

●愚直に書く

Gを2倍してRを引けば良さそう。

r = gets.to_i
g = gets.to_i

puts g * 2 - r

通った!

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

今回はメソッド化する余地もあまりないかな…。

リファクタリング/別アプローチ

リファクタリングも特に思いつかない…。標準入力を1行で取るとかはできるのかな。

●他の方の回答例

方針としては皆さん一緒だった。

コンパクトにまとめるなら以下のような感じ。

puts -gets.to_i+2*gets.to_i

なるほど。

●出てきたメソッド等

公式リファレンスを見る訓練。

今回特に無し!

■振り返りなど

  • 久しぶりだったので取っ付きやすい難易度で良かった。

以下テスト リンク