「第20回オフラインリアルタイムどう書く」の解答(改善?編)
前回の続きです。
finalfusionさんから次のアイデアをいただきました。
なるほど、たしかに。ありがとうございます。
というわけで、ジャマ川さんもとい座間川さんの予定だけ、trueとfalseを反転させようと考えました。
そのためには、配列の要素をすべて走査しなければなりません。……それはなんとなくイヤです。
配列をListに変換すれば、なんらかの便利メソッドが使えそうな気がします。しかし、配列はオートボクシングされないので、最初からBooleanの配列を使う必要があります。
でも"なんらかの便利メソッド"って何でしょう? booleanないしBooleanでは値が2種類しかありませんので、値の反転は面倒です(片方の値を退避できないため)。
諦めてビット使えや感が増してきましたが、それは無視して、方針を変えることにしました。やはりbooleanの配列がダメだったのです。そうだ、文字列を使おう。
こうなりました。
import java.util.*; public class Meetime { private static final char FREE = 'f'; private static final char BUSY = 'b'; public String solve(String input) { Map<Character, String> schedule = parse(input); List<Integer> meeting = new ArrayList<>(); meeting = check(schedule.get('A'), schedule.get('B'), schedule.get('I'), schedule.get('Z'), meeting); meeting = check(schedule.get('A'), schedule.get('B'), schedule.get('J'), schedule.get('Z'), meeting); Collections.sort(meeting); if (0 < meeting.size()) { return convertToTime(meeting.get(0)) + "-" + convertToTime(meeting.get(0) + 60); } return "-"; } List<Integer> check(String as, String bs, String xs, String zs, List<Integer> meeting) { int beginIndex = 0; int tmp = 0; for (int i = 60 * 10; i < 60 * 18; i++) { if (tmp == 0) { beginIndex = i; } if (as.charAt(i) == FREE && bs.charAt(i) == FREE && xs.charAt(i) == FREE && zs.charAt(i) == BUSY) { tmp++; } else { tmp = 0; beginIndex = 0; } if (59 < tmp) { meeting.add(beginIndex); tmp = 0; beginIndex = 0; } } return meeting; } Map<Character, String> initSchedule() { Map<Character, String> result = new HashMap<>(); result.put('A', new String(new char[1440]).replace('\0', FREE)); result.put('B', new String(new char[1440]).replace('\0', FREE)); result.put('I', new String(new char[1440]).replace('\0', FREE)); result.put('J', new String(new char[1440]).replace('\0', FREE)); result.put('Z', new String(new char[1440]).replace('\0', FREE)); return result; } Map<Character, String> parse(String input) { Map<Character, String> result = initSchedule(); String[] split = input.split(","); for (String str : split) { char name = str.charAt(0); String schedule = result.get(name); schedule = fill(schedule, convertToIndex(str.substring(1, 5)), convertToIndex(str.substring(6, 10))); result.put(name, schedule); } return result; } String fill(String schedule, int begin, int end) { StringBuilder sb = new StringBuilder(schedule); StringBuilder replaced = sb.replace(begin, end, new String(new char[end - begin]).replace('\0', BUSY)); return replaced.toString(); } String convertToTime(int index) { int hour = index / 60; int minute = index % 60; return String.format("%02d", hour) + String.format("%02d", minute); } int convertToIndex(String time) { int hour = Integer.parseInt(time.substring(0, 2)); int minute = Integer.parseInt(time.substring(2, 4)); return hour * 60 + minute; } }
Javaで「ある文字sをn個連結した文字列を作る」イディオムを探したところ、なるほどというアイデアを見つけたので、メモしておきます。
Here is the shortest version (Java 1.5+ required):
repeated = new String(new char[n]).replace("\0", s);
No imports or libraries needed.
Simple way to repeat a String in java - Stack Overflow
こりゃエレガントで素晴らしい方法だ!というレスがついててワロタです。これがJava…
Java 8でStringにjoinが入ったんだから、この手のメソッドを入れてくれてもいいのにと思います。
あ、肝心のジャマ川さんの反転は、次のように書けばできますが、
String zs = schedule.get('Z'); zs.replaceAll("f", "x"); zs.replaceAll("b", "f"); zs.replaceAll("x", "b");
checkメソッド内の条件式が次のようになるだけになってしまったので、
if (as.charAt(i) == FREE && bs.charAt(i) == FREE
&& xs.charAt(i) == FREE && zs.charAt(i) == FREE)
変更は見送りましたw