RustでAtCoderの過去問をやってみた
モダンな言語を使って他のエンジニアと差別化したいと思ったことはりませんか?
今回はモダンな言語であるRustで競技プログラミングAtcoderをやってみました。
なぜ競技プログラミングでRustなどのモダンな言語を使ったのかというと、モダン言語の書き方やアルゴリズムの組み方をトライアンドエラーしながら学習でき、点数として出来具合が表示されるため技術力に自信がつくと思ったからです。
前半ではRustとAtcoderについて、後半には実際にRustで回答したコードを記載しました。これを機にRustに挑戦してみましょう!
Rust
Rustの概要
Rustはメモリ安全性、並行性、およびパフォーマンスに焦点を当てて設計されたプログラミング言語で、Mozillaによって開発されました。GoogleやMicrosoftなど大手IT企業からエンジニアまでとても注目されている言語で、180ヶ国7万3,000人以上の開発者を対象に行った調査「Stack Overflow Developer Survey 2022」に7年連続で「開発者がもっとも愛するプログラミング言語」として選出されています。
Rustの良さがまとまっている記事があるので気になる方は下のサムネイルを見てみてください!
MicrosoftのRust講座
Microsoftにはプログラミングやインフラのトレーニングが用意されていて、Rustのチュートリアルもあります。
Rustの特徴を問題形式に出題されていたり手を動かしながらRustを勉強できるのでおすすめです。
手軽に始めるには
Rustを手軽に始めたい方はブラウザで実行できる「Rust Playground」があります。パソコンに実行環境を作る前に試したい方は活用してみましょう!
パソコンにインストールするには
パソコンにインストールして使ってみたい方は下のサムネイルを参考にしてみてください!
Atcoder
Atcoder概要
Atcoderは競技プログラミングサイトで、お題に沿って自分の好きな言語でプログラムを記載して点数を競うサイトです。
最近はプログラマー・エンジニアだけでなく、プログラミングに挑戦する未経験者も参加しています。プログラミングを学ぶことで論理的な思考や課題解決能力が上がります。
RustでAtcoderチュートリアルを解く
それではいよいよRustでAtcoderの問題を解いていきます。コードは以下の記事を参考にしてRustを書いていきました。
Atcoderの問題は下のサムネイルから見れます。
ABC086A - Product
use std::io;
fn main(){
// 1つ目の整数を受け入れる
let mut input_a_b = String::new();
io::stdin().read_line(&mut input_a_b).expect("Failed");
// 2つの整数を受け入れ、分割する
let mut iter = input_a_b.trim().split_whitespace();
let a:i32 = iter.next().expect("Failed").parse().expect("Failed");
let b:i32 = iter.next().expect("Failed").parse().expect("Failed");
// a と b の積が偶数か奇数か判定する
if (a *b %2) == 0{
println!("Even");
} else{
println!("Odd");
}
}
ABC081A - Placing Marbles
use std::io;
fn main(){
// 文字列を標準入力から読み取ります。
let mut s = String::new();
io::stdin().read_line(&mut s).expect("Failed");
// '1' の数を数えるためのカウンターを初期化します。
let mut count = 0;
// 各桁が '1' であるかをチェックし、カウンターを増やします。
if s.chars().nth(0) == Some('1') {count += 1}
if s.chars().nth(1) == Some('1') {count += 1}
if s.chars().nth(2) == Some('1') {count += 1}
// 結果を出力します。
println!("{}",count)
}
ABC081B - Shift only
use std::io;
fn main(){
// 整数を受け入れる
let mut input_n = String::new();
io::stdin().read_line(&mut input_n).expect("Failed");
let n:usize = input_n.trim().parse().expect("Failed");
// 受け入れた整数を配列にする
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed");
let mut a:Vec<i32> = input
.trim()
.split_whitespace()
.map(|x| x.parse().expect("Failed"))
.collect();
// 出力する整数を初期化
let mut res = 0;
// 操作回数を判定
for _ in 0..n{
let mut exist_odd = a.iter().any(|x| x % 2 != 0 );
if exist_odd {
break;
}
for i in 0..n {
a[i] /= 2;
}
res += 1;
}
println!("{}",res);
}
ABC087B - Coins
use std::io;
fn main(){
// 500 円玉の最大枚数を入力する
let mut input_a = String::new();
io::stdin().read_line(&mut input_a).expect("Failed A");
let a:i32 = input_a.trim().parse().expect("Failed parse A");
// 100 円玉の最大枚数を入力する
let mut input_b = String::new();
io::stdin().read_line(&mut input_b).expect("Failed B");
let b:i32 = input_b.trim().parse().expect("Failed parse B");
// 50 円玉の最大枚数を入力する
let mut input_c = String::new();
io::stdin().read_line(&mut input_c).expect("Failed C");
let c:i32 = input_c.trim().parse().expect("Faild parse C");
// 合計金額を入力する
let mut input_x = String::new();
io::stdin().read_line(&mut input_x).expect("Failed X");
let x:i32 = input_x.trim().parse().expect("Failed parse X");
// 何通りあるかのカウントを初期化する
let mut res = 0;
// 500 * A + 100 * B + 50 * C == X だったらポイント
// そうではなかったらパス
for i in 0..=a{
for j in 0..=b{
for k in 0..=c{
let total = 500 * i + 100 * j + 50 * k;
if total == x{
res += 1;
}
}
}
}
// 何通りあるか出力する
println!("{}",res);
}
ABC083B - Some Sums
use std::io;
// 各桁の和を計算する関数
fn add_num(mut n:u32)->u32{
let mut sum:u32 = 0;
while n > 0{
sum += n % 10;
n /= 10;
}
sum
}
fn main(){
// 数値を取り込み
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
// 分割する
let mut iter = input.trim().split_whitespace();
let mut n:u32 = iter.next().unwrap().parse().unwrap();
let mut a:u32 = iter.next().unwrap().parse().unwrap();
let mut b:u32 = iter.next().unwrap().parse().unwrap();
let mut total:u32 = 0;
// 和が A 以上 B 以下である数値の総和
for i in 1..=n{
let sum = add_num(i);
if a <= sum && sum <= b {
total += i
}
}
println!("{}",total)
}
ABC088B - Card Game for Two
use std::io;
fn main() {
// 数値を取り込み
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let n: usize = input.trim().parse().expect("Failed to parse input as integer");
// 数値を取り込み
input.clear();
io::stdin().read_line(&mut input).unwrap();
// 配列に格納する
let mut a: Vec<i32> = input
.trim()
.split_whitespace()
.map(|x| x.parse().expect("Failed to parse input as integer"))
.collect();
// 大きい順にソート
a.sort_by(|a, b| b.cmp(a));
let mut alice = 0;
let mut bob = 0;
// 振り分け
for (i, &num) in a.iter().enumerate() {
if i % 2 == 0 {
alice += num;
} else {
bob += num;
}
}
println!("{}", alice - bob);
}
ABC085B - Kagami Mochi
use std::io;
use std::collections::HashSet;
fn main(){
// 数値を入力
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed read line");
let n:usize = input.trim().parse().unwrap();
let mut list:Vec<usize> = Vec::new();
// 入力された数値を配列に格納する
for _ in 0..n{
input.clear();
io::stdin().read_line(&mut input).expect("Failed read line");
let n:usize = input.trim().parse().unwrap();
list.push(n);
}
// 重複しない数値にする
let res:HashSet<usize> = list.into_iter().collect();
println!("{}",res.len());
}
ABC085C - Otoshidama
use std::io;
fn main(){
// 入力された文を分割する
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed read line");
let mut iter = input.trim().split_whitespace();
// 分割した数値をそれぞれの変数に格納する
let number:i32 = iter.next().unwrap().parse().unwrap();
let yen:i32 = iter.next().unwrap().parse().unwrap();
// 初期値を設定する
let mut res10000 = -1;
let mut res5000 = -1;
let mut res1000 = -1;
// 条件に合う枚数を計算する
for a in 0..=number{
for b in 0..=number-a{
let c = number - a - b;
let total = 10000 * a + 5000 * b + 1000 * c;
if total == yen{
res10000 = a;
res5000 = b;
res1000 = c;
}
}
}
println!("{} {} {}",res10000,res5000,res1000);
}
ABC049C - 白昼夢
use std::io;
fn main(){
// 入力の読み取り
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed read line");
// 文字列をリバースする
let input_rev:String = input.trim().chars().rev().collect();
// 各要素をリバースする
let divide:Vec<String> = vec!["dream", "dreamer", "erase", "eraser"]
.iter()
.map(|&d| d.to_string().chars().rev().collect() )
.collect();
// 端から切っていく
let mut can = true;
let mut i = 0;
while i < input_rev.len(){
let mut can2 = false;
for d in ÷{
if input_rev[i..].starts_with(d){
can2 = true;
i += d.len();
break;
}
}
if !can2{
can = false;
break;
}
}
// 結果の出力
if can {
println!("YES");
}else{
println!("NO");
}
}
ABC086C - Traveling
use std::io;
pub fn main() {
// 値を入力する
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed read line");
let n:usize = input.trim().parse().unwrap();
let mut plans:Vec<(i64,i64,i64)> = Vec::new();
// 数値をタプルにして配列に格納する
for _ in 0..n {
input.clear();
io::stdin().read_line(&mut input).expect("Failed read line");
let mut iter = input.trim().split_whitespace();
let t:i64 = iter.next().unwrap().parse().unwrap();
let x:i64 = iter.next().unwrap().parse().unwrap();
let y:i64 = iter.next().unwrap().parse().unwrap();
plans.push((t,x,y));
}
let mut t_0 = 0;
let mut x_0 = 0;
let mut y_0 = 0;
let mut res = "Yes";
// 旅行プランを判定する
for plan in plans {
let (t_1, x_1, y_1) = (plan.0, plan.1, plan.2);
let elapsed_time = t_1 - t_0;
let distance = (x_1 - x_0).abs() + (y_1 - y_0).abs();
if (elapsed_time - distance < 0) || ((elapsed_time - distance) % 2 != 0) {
res = "No";
break;
}
t_0 = t_1;
x_0 = x_1;
y_0 = y_1;
}
println!("{}", res);
}
学習で使った教材
Rust本
Rustを勉強する必要性やRustプログラミングの基礎から簡単なWebアプリやWebAssemblyなどの高度な技術までをまとめた本です。Pythonで書かれたコードと比較しながら勉強できるのでどのようなコードの作りをしているのかがわかってとても参考になります。Rustの基礎から応用までをじっくりやりたい方におすすめです。
アルゴリズム本
アルゴリズムを数学で解説してくれる本。Atcoderの機能を使って本の演習が解けるので知識のインプットだけでなくアウトプットにも活用できる良本です。アルゴリズムの基礎を鍛えたい方や効率的なコードの書き方を学びたい方におすすめです。
Rust動画
動画で学べるプラットフォーム「Udemy」でもRustを学べます。講師と一緒にRustを動かすので書籍ではわからない細かい動作や豆知識が学べます。このコースでは家計簿アプリをRustで作成するセクションがあるのでとても勉強になります。書籍だとあまり学習が進まないけど勉強はしたいという方におすすめです。
未経験からのITエンジニア
IT技術の進化速度が速くなっていっている今、IT技術にアンテナを張っておくことはとても重要です。エンジニアになろうとしている方やそうではない方もITスキルを磨くことで問題解決能力や論理的思考を養うことができます。複雑な課題に対処し、効果的な解決策を見つける能力はどの職種でも重宝されます。
そこで、エンジニア未経験の時にあったらよかったなと思っていた講座をマガジンにまとめました!アプリの基礎がわかるTodoアプリの開発からGit&GitHubでのチーム開発までエンジニアに必要な知識が詰まっています!
エンジニアリングの第一歩として使ってみてください!
「売上げアップに効果的」なキャッチコピーやテキストを作成してくれる国内最大級の「AIコピーライティングツール」
【Catchy】
会議・ミーティングの内容をリアルタイムで文字に起こすAI自動文字起こしサービス
【Notta】
ブログの記事制作にかかる時間を1/10で制作できる高品質SEO記事生成AIツール
【Value AI Writer byGMO】