Java向け競プロライブラリ(二分探索)

java.util.ArraysクラスにbinarySearchメソッドは実装されていますが、「keyで指定された要素を複数持つ場合にはどれが返されるか保証されていない」という使い道に困り果てそうな実装であるため、自前でライブラリを持っておくべきかと思われます

Arrays (Java SE 11 & JDK 11 )

※2023/09/22追記およびコード修正:型パラメータを使用して汎用性を持たせました(配列で書くことも不可能ではありませんが、T[]型を引数として渡すようにするとプリミティブ型配列を引数として与えた時にコンパイルエラーとなり、ラッパークラス型配列を渡さなければ正常実行が不可能であるのみならず、プリミティブ型配列を引数とするArrays#sortは改良版のクイックソートにより実装されており、最悪n^2に比例する実行時間を要してTLEする可能性を孕んでいるため、各データをプリミティブ型で保存する意思を最初から捨ててマージソートにより実装された並べ替え処理を確実に呼び出すためにリストで実装する方が良いと判断しました)

 

 

import java.util.List;

public final class BinarySearcher {

	/**
	 * 昇順ソート済みのリストに対して二分探索を実行し、
	 * key <= list.get(index)
	 * となるような最小のindexを返す
	 * @param <T> リストの各要素の型
	 * @param list 探索対象のリスト
	 * @param key 探索キー
	 * @return 適切な要素が存在する場合は最小のインデックス、存在しない場合は-1
	 */
	public static <T extends Comparable<T>> int findSmallestIndexGreaterThanOrEqualToKey(List<T> list, T key) {
		return findSmallestIndexGeneral(list, key, true);
	}

	/**
	 * 昇順ソート済みのリストに対して二分探索を実行し、
	 * key < list.get(index)
	 * となるような最小のindexを返す
	 * @param <T> リストの各要素の型
	 * @param list 探索対象のリスト
	 * @param key 探索キー
	 * @return 適切な要素が存在する場合は最小のインデックス、存在しない場合は-1
	 */
	public static <T extends Comparable<T>> int findSmallestIndexGreaterThanKey(List<T> list, T key) {
		return findSmallestIndexGeneral(list, key, false);
	}

	/**
	 * 昇順ソート済みのリストに対して二分探索を実行し、
	 * list.get(index) <= key
	 * となるような最大のindexを返す
	 * @param <T> リストの各要素の型
	 * @param list 探索対象のリスト
	 * @param key 探索キー
	 * @return 適切な要素が存在する場合は最大のインデックス、存在しない場合は-1
	 */
	public static <T extends Comparable<T>> int findLargestIndexLessThanOrEqualToKey(List<T> list, T key) {
		return findLargestIndexGeneral(list, key, true);
	}

	/**
	 * 昇順ソート済みのリストに対して二分探索を実行し、
	 * list.get(index) < key
	 * となるような最大のindexを返す
	 * @param <T> リストの各要素の型
	 * @param list 探索対象のリスト
	 * @param key 探索キー
	 * @return 適切な要素が存在する場合は最大のインデックス、存在しない場合は-1
	 */
	public static <T extends Comparable<T>> int findLargestIndexLessThanKey(List<T> list, T key) {
		return findLargestIndexGeneral(list, key, false);
	}

	private static <T extends Comparable<T>> int findSmallestIndexGeneral(List<T> list, T key, boolean isInclusive) {
		int left = -1, right = list.size();
		while (right - left > 1) {
			int mid = (left + right) / 2;
			if (isInclusive ? key.compareTo(list.get(mid)) <= 0 : key.compareTo(list.get(mid)) < 0) {
				right = mid;
			} else {
				left = mid;
			}
		}
		return right == list.size() ? -1 : right;
	}

	private static <T extends Comparable<T>> int findLargestIndexGeneral(List<T> list, T key, boolean isInclusive) {
		int left = -1, right = list.size();
		while (right - left > 1) {
			int mid = (left + right) / 2;
			if (isInclusive ? list.get(mid).compareTo(key) <= 0 : list.get(mid).compareTo(key) < 0) {
				left = mid;
			} else {
				right = mid;
			}
		}
		return left;
	}

}

Excelメモ:数式によりシート内の範囲を図として挿入

※タイトルのことを実現したい時の手順を何度も忘れてしまって非生産的すぎたため備忘録として残しておきます(ほとんど自分用のメモです)

 

1)「挿入」→「図の挿入」を使い、貼り付け先のシートにダミーの図を挿入

 

2)上記手順1)でセットした図をクリックして選択した状態にし、数式ウインドウに図として挿入したいシートの範囲を数式で指定する

※元になるシートの名前を仮に「src」とした場合、「=src!$A$1:$D$25」などのように入力すればOK。以上の手順に従うと、src側の指定範囲に編集を加えた場合、貼り付けた図の方にも変更が反映されるのが便利

ルータを認識しているのにネットに繋がらない現象の解決

(解決まで1日まるごと苦しんだので備忘録として残しておきます)

 

結論としては、アクセスする側のマシンやルータ自身の設定値が狂っていたわけでも何でもなく、ルータにケーブルを繋ぎ直す際、誤って「INTERNET」ポートにモデム以外のケーブルを繋いでしまっていたというだけのことでした(情けない限りです)。

※ルータ付近にたまっていた埃を掃除するためにケーブルをすべて外したのち、繋ぎ直す際にポートを間違えてしまったものと予想しています。

 

ちなみに、ケーブルを挿し込むポートを間違えているうちはGoogleでの検索は可能ですが、タイムアウトエラーになり(応答時間が長すぎます。という趣旨のメッセージが表示される)各ページの内容を閲覧できなくなっていました。

皆さんも同じような現象に出くわした際は、各マシンの設定値が間違っているかどうかを疑う前にモデムのケーブルがルータの「INTERNET」ポートに正しく繋がっているかどうかを確かめてみてください。

 

--- 以下雑記 ---

プロバイダにネット料金を支払う際、払込票で支払うようにしていると、私のように無限先延ばしをしたのちに回線を止められるという間抜けムーブをかますことになるので、支払方法として指定するのは絶対に口座からの自動引き落としにしましょう。

Javaで日付を表す文字列がカレンダーに即しているか判定する

見出しの通りの機能を持つクラスです。必要に応じてYMDのパターンと正規表現を追加していけばいい感じに使えると思います。isOnCalendarメソッドを呼び出せば判定できます。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Optional;

public class DateValidator {

	private DateValidator() {
		throw new IllegalStateException("Cannot instantiate " + DateValidator.class.getName());
	}

	public static boolean isOnCalendar(String date) {
		if (date == null) {
			return false;
		}

		Optional<RegexYmdPatternPair> ryppCorrespondingToDate = Arrays.stream(RegexYmdPatternPair.values())
				.filter(p -> date.matches(p.regex)).findFirst();

		if (ryppCorrespondingToDate.isEmpty()) {
			return false;
		}

		try {
			createStrictSimpleDateFormat(ryppCorrespondingToDate.get().ymdPattern).parse(date);
		} catch (ParseException e) {
			return false;
		}

		return true;
	}

	private static SimpleDateFormat createStrictSimpleDateFormat(String ymdPattern) {
		SimpleDateFormat sdf = new SimpleDateFormat(ymdPattern);
		sdf.setLenient(false);
		return sdf;
	}

	private enum RegexYmdPatternPair {

		WITHOUT_SEPARATOR("^[0-9]{8}$", "yyyyMMdd"),
		SEPARATED_BY_HYPHEN("^[0-9]{4}-[0-9]{2}-[0-9]{2}$", "yyyy-MM-dd"),
		SEPARATED_BY_SLASH("^[0-9]{4}/[0-9]{2}/[0-9]{2}$", "yyyy/MM/dd");

		private final String regex;
		private final String ymdPattern;

		private RegexYmdPatternPair(String regex, String ymdPattern) {
			this.regex = regex;
			this.ymdPattern = ymdPattern;
		}

	}

}

EclipseとWebSphere Libertyを使ったWebアプリケーション開発環境構築

※自分用のメモも兼ねています

 

1.Eclipseをインストール

Pleiades All in Oneダウンロードを使ってFull Editionを取得(ゆとりとか言うのはNG)

https://mergedoc.osdn.jp/

f:id:JunKobayashi:20200325172011p:plain

Fig. 1 Pleiadesを利用しEclipseを取得

f:id:JunKobayashi:20200325172119p:plain

Fig. 2 各人のOSに合わせて取得(私は64bit Windows)

 

Eclipseをインストールし画面の色だのフォントだのの設定をお好みに整える。

 

2.WebSphere Libertyパッケージのダウンロード

参考リンク1)の記事のリンク( https://www.ibm.com/support/pages/node/587599 )からwlp-javaee7-16.0.0.3.zipをダウンロードして解凍(IBMアカウントを持っている必要があるためなければ新規作成する)。ちなみにディレクトリ構造は参考リンク2)の記事を参考にして作成した。

f:id:JunKobayashi:20200325172720p:plain

Fig. 3 WebSphere Libertyのダウンロード

 

3.Eclipseマーケットプレースで関連ツールをインストール

マーケットプレースで以下の追加プラグインをインストール(これらのインストール後Eclipseを再起動)

  • IBM Lberty Developer Tools 20.0.0.3
  • IBM WebSphere Application Server Liberty Developer Tools Beta 20.0.0.3

f:id:JunKobayashi:20200325173252p:plain

Fig. 4 WebSphere Liberty 関連ツールをインストール

 

 

4.ランタイム環境の構成

Runtime Explorerビューを開き右クリック→新規→ランタイム環境で新規ランタイム環境を作成する。Choose an existing installationから[ダウンロード後に解凍したwlpバージョン名]\wlpを指定し、他の設定はデフォルトのままにした。

f:id:JunKobayashi:20200325173825p:plain

Fig. 5 新規Libertyランタイム環境作成

 

5.新規Libertyサーバーの構築

サーバービューを開きLiberty Runtimeを右クリック→新規→Liberty Serverをクリックし新規Libertyサーバーを作成(設定はサーバー名をTestServerにした以外は全てデフォルト)。

f:id:JunKobayashi:20200325174223p:plain

Fig. 6 新規Libertyサーバー作成

 

f:id:JunKobayashi:20200325192937p:plain

Fig. 7 新規サーバー設定

 

6.テスト

参考リンク1)の記事に従って動的Webプロジェクト(Sample02)を作り、それをTestServerに乗せ(サーバービューでTestServerを右クリック→追加および除去から可能)サーバー起動。すると以下のようにコンソールログが文字化けしていたのとNoClassDefFoundErrorによりサーバー起動に失敗した。

f:id:JunKobayashi:20200325193418p:plain

Fig. 8 サーバー起動失敗時のコンソール

 

7.サーバーログ文字化け解決

参考リンク3)に倣い、wlp\usr\servers\TestServerに、以下の内容を記述したjvm.optionsを配置した(Windowsでは文字コード設定がデフォルトではSJISに指定されているため発生するらしい)。

 

-Dfile.encoding=UTF-8

 

 

8.追加プラグインをインストールしサーバー起動失敗の解決

マーケットプレイスから追加でIBM WebSphere Application Server V8.5x Developer Tools 20.0.0.3をインストールした。

f:id:JunKobayashi:20200325194117p:plain

Fig. 9 IBM WebSphere Application Server V8.5x Developer Tools のインストール

また、Sample02プロジェクトを右クリック→プロパティからプロジェクトファセット、ビルド・パス、コンパイラー準拠レベル、およびウインドウ→設定→Java→インストール済みのJREの各項目を全てJava8準拠のものに設定変更した(私のインストールしたEclipse 2019ではこれらの設定がデフォルトでJava11準拠のものであった)

f:id:JunKobayashi:20200325194547p:plain

Fig. 10 プロジェクトファセットにてJavaを1.8に設定

f:id:JunKobayashi:20200325194633p:plain

Fig. 11 ビルド・パスの設定にてJava8に設定

f:id:JunKobayashi:20200325194723p:plain

Fig. 12 コンパイラー準拠レベルを1.8に設定

f:id:JunKobayashi:20200325194808p:plain

Fig. 13 インストール済みのJREをJava8に設定

以上の手順を行って、サーバー起動に成功し、クエリパラメータの値に応じた動的なWebページを開くことができることを確認した。

※ほかのWindows10マシンでも同様の手順を踏んだのだがこのプラグインを入れず、Javaバージョン設定を特に変えずとも実行に成功したため正直何が原因だったのか分からない・・・

 

9.サーバー通信におけるセキュリティ設定

マーカービューを見るとLiberty サーバーの構成定義に関する項目で警告が発生していた。

f:id:JunKobayashi:20200325195719p:plain

Fig. 14 Liberty サーバーの構成定義に関する警告

クイックフィックスを利用。server.xmlにkeyStore要素がない(このサーバーと通信する際に特に証明書等必要としないためセキュリティ上の懸念があるということ?)のがよろしくないため設定を行う。

f:id:JunKobayashi:20200325200025p:plain

Fig. 15 クイックフィックスのウインドウ(右下の完了を押す)

f:id:JunKobayashi:20200325200113p:plain

Fig. 16 keyStore設定ウインドウ(設定を押す)

この後の画面でパスワードを設定(エンコードはデフォルトのxorのまま、キーは空欄のままで完了を押しdefaultKeyStoreとなった)。server.xmlに以下のように追記される。参考リンク4)を参照されたし。

 

<keyStore id="defaultKeyStore" password="{xor}XXXXXXXXXXXXXXX"/>

 

この状態でもう一度サーバー起動、動的Webページの表示が可能であることを確認し、環境構築手順を完了したと判断した。
 

参考リンク

  1. https://qiita.com/tomotagwork/items/ef1c1ebc5efa2a8935d9 (WebSphere Liberty for Windows 開発環境整備手順 - Qiita
  2. https://www.ibm.com/developerworks/jp/websphere/library/was/liberty_devenv_install/ (WebSphere LibertyのJava EEローカル開発環境のインストール
  3. https://qiita.com/asmanabu/items/a95dec97aabddd69acd8 (Bluemix Liberty for Javaの開発環境を整える(1/3) - Qiita
  4. https://qiita.com/tomotagwork/items/3a63ac7955d053a4feb4 (LibertyによるWebサービスアプリ開発メモ: (1)環境構築 - Qiita