やっとこさMLEから抜け出した話

前回の記事で発生したMLEがなんとか解決できたので報告します。

よかったら前回の記事も見てください。

y-koki1023.hatenablog.com

前回までの問題点

コードの判定の際に一部のケースでMLE(メモリ超過?)が発生した

理由はよくわからないが 要するに無駄が多いってことだろう(ヤケクソ)

今回の解決プラン

  1. 不要なメソッドの呼び出し回数を減らす。
  2. 判定に必要な文字列の改善
  3. 無駄そうなところを減らす(適当)

改善後のコード

import java.util.Arrays;
import java.util.Scanner;
public class Main {
    static String T = "";

    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String[] strs = str.split("");
        String temp = "";
        for(int i = 0; i < strs.length;){
            if(strs[i].equals("d")){
                temp = checkDream(i,strs);
                if(!temp.equals( "error")){
                    T += temp;
                }else{
                    System.out.println("NO");
                    return;
                }
            }else if(strs[i].equals("e")){
                temp = checkErase(i,strs);
                if(!temp.equals("error")){
                    T += temp;
                }else{
                    System.out.println("NO");
                    return;
                }
            }else{
                System.out.println("NO");
                return;
            }
            i = T.length();
        }
        if(T.equals(str)){
            System.out.println("YES");
        }else{
            System.out.println("NO");
        }
    }
    public static String checkDream(int index, String[] strs){
        String temp = "";
        try{
            /*
            for(int i = index; i < index + 5;i++){
                temp = temp + strs[i];
            }
            */
            String copy[] = Arrays.copyOfRange(strs,index,index+5);
            temp = String.join("",copy);
             if(temp.equals("dream")){
                temp += strs[index + 5] + strs[index + 6];
                if(temp.equals("dreamer")){
                    temp = checkErase(index + 5,strs);
                    if( temp != "error"){
                        return "dream" + temp;
                    }else{
                        return "dreamer";
                    }
                }else{
                    return "dream";
                }
            }else{
                return "error";
            }
        }catch(Exception e){
            if(!temp.equals("dream")){
                return "error";
            }else{
                return "dream";
            }
        }


    }

    public static String checkErase(int index, String[] strs){
        String temp = "";
        try{
            /*
            for(int i = index; i < index + 5;i++){
                temp = temp + strs[i];
            }
            */
            String copy[] = Arrays.copyOfRange(strs,index,index+5);
            temp = String.join("",copy);
            if(temp.equals("erase")){
                temp += strs[index + 5];
                if(temp.equals("eraser")){
                    return "eraser";
                }else{
                    return "erase";
                }
            }else{
                return "error";
            }
        }catch(Exception e){
            if(!temp.equals("erase")){
                return "error";
            }else{
                return "erase";
            }
        }


    }

}

結果は....?

問答無用のMLEでした....
本当にビギナー用なんだろうか
どうしようもなくなった僕はフラグ建築士1級の友人Yに教えてもらった
"文字列後ろから見れば判定楽じゃね?" 戦法にシフトすることにしました。

文字列後ろから見れば判定楽じゃね? とは

入力される文字列を後ろから判定していくことで、前から判定していくときに必要だった "dreamer" の"er" + 後の3文字から "erase" を判定する手間を省くことができる素晴らしい技法である。

実際に書いてACだったコード

import java.util.Arrays;
import java.util.Scanner;
public class Main {
    static String T = "";

    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String keyWords[] = {"dream","dreamer","erase","eraser"};
        //sub_Stringの呼び出しが多い問題?
        int length = str.length();
        while(length > 0){
            String temp = str.substring(length - 5,length);
            if(length - 5 >= 0 ) {
                if (temp.equals(keyWords[0]) || temp.equals(keyWords[2])) {
                    length -=5;
                    continue;
                }
            }
            temp = str.substring(length -6 ,length);
            if(length - 6 >= 0 && temp.equals(keyWords[3])){
                length -=6;
                continue;
            }
            temp = str.substring(length - 7,length);
            if(length- 7 >= 0 &&temp.equals(keyWords[1])){
                length -=7;
                continue;
            }else{
                System.out.println("NO");
                return;
            }

        }
        System.out.println("YES");
    }
}

教訓

急がば回れ これに尽きる
問題を解くためゴリ押しした結果メモリを大量に使う消費文化もびっくりなコードを書いてしまった。
書くまえに無駄な処理が多くないか、方法自体がゴリ押しすぎないかを確認してからコードを書くことで今回のようなことが起こらないように心掛けたい(絶対やらかす btw
友人Yありがとう。