1. 基数変換(基礎レベル)
この問題は、ある基数で表された数値を別の基数に変換するものです。まずは、手動で変換処理を実装した例とその課題を見てみましょう。この方法は基数変換の仕組みを理解するのに役立ちますが、実装が複雑でエラーが発生しやすく、処理時間もかかります。
import java.util.Scanner;
import static java.lang.Math.*;
public class BaseConversionManual {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 入力データの読み込み
int sourceRadix = scanner.nextInt();
StringBuilder inputNumber = new StringBuilder(scanner.next().toUpperCase());
int targetRadix = scanner.nextInt();
long decimalValue = 0;
// 入力された数値を10進数に変換
if (sourceRadix != 10) {
decimalValue = convertToDecimal(sourceRadix, inputNumber);
} else {
// 10進数の場合の処理
decimalValue = Long.parseLong(inputNumber.toString());
}
StringBuilder outputNumber = new StringBuilder();
// 10進数を目的の基数に変換
if (targetRadix != 10) {
outputNumber.append(convertFromDecimal(targetRadix, decimalValue));
} else {
outputNumber.append(inputNumber.toString().toUpperCase());
}
System.out.println(outputNumber.toString().toUpperCase());
}
// 任意の基数から10進数への変換
public static long convertToDecimal(int radix, StringBuilder sb) {
long value = 0;
for (int i = 0; i < sb.length(); i++) {
char c = sb.charAt(i);
if (c >= 'A' && c <= 'F') {
value += (long) ((c - 'A' + 10) * pow(radix, sb.length() - i - 1));
} else {
value += (long) ((c - '0') * pow(radix, sb.length() - i - 1));
}
}
return value;
}
// 10進数から任意の基数への変換
public static String convertFromDecimal(int radix, long num) {
StringBuilder sb = new StringBuilder();
while (num > 0) {
long remainder = num % radix;
if (remainder >= 10) {
char c = (char) ('A' + remainder - 10);
sb.append(c);
} else {
sb.append(remainder);
}
num /= radix;
}
return sb.reverse().toString();
}
}
上記の方法は、基数変換の基本を理解する良い練習ですが、Javaの標準ライブラリを活用することで、より簡潔で効率的なコードを書くことができます。`java.math.BigInteger`クラスは、基数変換を非常に簡単に行うための便利なメソッドを提供しています。
import java.util.Scanner;
import java.math.BigInteger;
public class BaseConversionOptimized {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 入力データの読み込み
int sourceRadix = scanner.nextInt(); // 元の基数
String inputNumber = scanner.next(); // 元の数値
int targetRadix = scanner.nextInt(); // 変換後の基数
// 元の基数の数値を10進数のBigIntegerに変換
BigInteger bigIntegerValue = new BigInteger(inputNumber, sourceRadix);
// 10進数のBigIntegerを目的の基数の文字列に変換
String convertedNumber = bigIntegerValue.toString(targetRadix);
System.out.println(convertedNumber.toUpperCase());
}
}
2. 箸を探す(基礎レベル)
この問題は、N本の箸の中から、1本だけペアのない箸を見つけるものです。最初に試したアプローチでは、すべての箸を配列に格納し、重複をチェックする方法を取りましたが、これはメモリ使用量が多すぎて実行時エラー(MLE)になりました。
import java.util.Scanner;
public class FindChopstickInitial {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] chopsticks = new int[n];
for (int i = 0; i < n; i++) {
chopsticks[i] = scanner.nextInt();
}
int singleChopstick = 0;
// ペアの箸を特定し、マーク(0)する
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (chopsticks[i] == chopsticks[j]) {
chopsticks[i] = 0;
chopsticks[j] = 0;
break;
}
}
}
// マークされていない(0でない)箸が答え
for (int i = 0; i < n; i++) {
if (chopsticks[i] != 0) {
singleChopstick = chopsticks[i];
break;
}
}
System.out.println(singleChopstick);
}
}
この問題は、XOR(排他的論理和)演算を利用することで、メモリを節約し、非常に効率的に解決できます。XORは、同じ値同士の演算結果が0、異なる値同士の演算結果が1になるという性質を利用します。この性質により、すべての箸の長さをXOR演算で組み合わせると、ペアの箸は0になり、唯一のペアのない箸の長さだけが残ります。
import java.util.Scanner;
public class FindChopstickXOR {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int result = 0;
for (int i = 0; i < n; i++) {
result ^= scanner.nextInt();
}
System.out.println(result);
}
}