Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

【AtCoder】超初心者のためのAtCoder Beginner Contest 397A,B問題復習・解説【Java】【ABC397】

Last updated at Posted at 2025-03-16

はじめに

オムロンプログラミングコンテスト2025(AtCoder Beginner Contest 397) - AtCoderにJavaで出ました。
ほぼ3年ぶりの参加&Javaでの参加は初めてだったため、A,Bは解けましたが、Cまで到達することができませんでした。
備忘録としてまとめておきます。
一部、ChatGPTを用いている箇所があるため、限定公開記事としています。
(きちんと使用箇所には明記しています)

A - Thermometer

私の回答

import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    // 整数の入力
    double x = sc.nextDouble();
    // 結果を出力する
    if(x>=38.0){
        System.out.println("1");
    }else if(x<38.0 && x>=37.5){
        System.out.println("2");
    }else {
        System.out.println("3");
    }
  }
}

解説

公式の解説は解説 - オムロンプログラミングコンテスト2025(AtCoder Beginner Contest 397)です。
この問題は、以下の3つのパターンをただif文を使って、以下のように出力するだけです。

  • 38.0℃以上のとき:1を出力
  • 37.5℃以上38.0℃未満:2を出力
  • 37.5℃未満:3を出力

B - Ticket Gate Log

自分の回答(変な解き方です)

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        // 文字列の入力
        String inputStr= sc.nextLine();
        // 文字列を入れるための配列
        String x = inputStr.replaceAll("io", "*");
        int count = 0;
        for(int i=0;i<x.length();i++){
            if(x.charAt(i)=='*'){
                count++;
            }
        }
        System.out.println(x.length()-count);
    }
}

ioじゃないところだけ変更するということだと考え、以下のように解いたらACでした。
多分変な解き方です。

  1. ioの部分を*に置換
  2. 文字列の長さから、*の個数を引く

回答(公式C++の回答をJavaにしたもの)

ChatGPTを用いて公式C++の回答をJavaにしています。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String S = scanner.next();
        int ans = 0;
        char target = 'i';

        for (char c : S.toCharArray()) {
            if (c == target) {
                target = (target == 'i') ? 'o' : 'i';
            } else {
                ans++;
            }
        }

        if (target == 'o') {
            ans++;
        }

        System.out.println(ans);
        scanner.close();
    }
}

解説

S を前から見て行って,今見ている場所までの文字列が条件を満たすような最小の操作回数を考えます.
次に現れる必要がある文字 t(最初は t=i)を管理しながら,S を前から見ていきます.
S の今見ている文字が,t に一致するならば,すでに条件を満たします.
t を反転させて(i ならば o に,o ならば i にする),S の次の文字を見ます.

S の今見ている文字が,t と異なるならば,t を今見ている文字の前に挿入する必要があります.この操作によって,今見ている文字までの条件が満たされます.このとき,答えに 1 を足し,t を変えずにS の次の文字を見ます.

最後に,S の最後の文字が i ならば,その後ろに o を挿入する必要があるので,答えに 1 を足します.

引用:解説 - オムロンプログラミングコンテスト2025(AtCoder Beginner Contest 397)

三項演算子について

1.変数1が「ほげ1」と同じだったら変数2に「ほげ2」を入れてね
2.違ったら変数2に「ほげ3」を入れてね

これを三項演算子を使って書くと

変数2(変数1=="ほげ1") ? "ほげ2" : "ほげ3"

引用:三項演算子とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

つまり、target = (target == 'i') ? 'o' : 'i';は、以下となります。

  1. targetiだったらtargetoを入れてね
  2. 違ったらtargetiを入れてね

charArrayについて

以下のように書くと、helloを1文字ずつ分割して、cArrayに順番に格納します。

public class Main {
  public static void main(String[] args) {
    String str1 = "hello";
    char[] cArray;
    cArray = str1.toCharArray();
    for (char c : cArray) {
      System.out.println(c);
    }
    System.out.println();
  }
}

参考:【Java】toCharArrayメソッドで文字列を配列に分割する - Dim雑記

出力結果
h
e
l
l
o

ChatGPTによる更にわかりやすい解説

このプログラムの動きを、小学生でもわかるように順序立てて説明します!😊

📝 何をするプログラム?

このプログラムは、文字列の中から 「i → o → i → o → …」 という交互のパターンを作るために、いくつの文字を消せばいいかを数えるものです。


🏃‍♂️ プログラムの流れ

  1. 入力を受け取る

    • 例えば、ユーザーが「iiioooii」と入力したとします。
  2. 変数を準備する

    • ans = 0 (答えを入れる箱。最初は0)
    • target = 'i' (最初に探す文字は 'i')
  3. 1文字ずつチェック

    • 文字列の最初から順番に見ていく。
    • もし target の文字なら、次に探す文字を 'i' ⇄ 'o' に変える
    • 違う文字なら、それは不要なので ans を増やす
  4. 最後に target が 'o' だったら ans を増やす

    • ちゃんと「i → o → i → o …」と続いていれば OK。
    • 途中で終わっていたら、最後に 'o' を足して完成させるために ans++ する。
  5. 答えを出力する


🔍 実際の動き(例)

例えば「iiioooii」を入力すると、次のように進みます。

文字 target 処理 ans
i i OK → 次は o を探す 0
i o ダメ → ans++ 1
i o ダメ → ans++ 2
o o OK → 次は i を探す 2
o i ダメ → ans++ 3
o i ダメ → ans++ 4
i i OK → 次は o を探す 4
i o ダメ → ans++ 5

最後の target は 'o' なので ans++ して 答えは 6


💡 ポイント

  • target の文字が交互に変わる(i → o → i → o)。
  • その順番にならない文字を消すことで、正しいパターンにする。
  • 最後に target が 'o' のままなら ans++ して調整。

🏆 結論
このプログラムは、「i → o → i → o …」の並びにするために、最小限の削除回数を求めるプログラム です!💡

終わりに

会社でJavaを学ぶことになり、その実践として久しぶりにAtCoderに参加したものの、解法が思いつかないことが多々ありました。
そこで、今後はもう少しABCの過去問を解いていこうと思います。
この記事が参考になれば幸いです。
ここまで読んでいただきありがとうございました。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?