- 投稿日:2019-04-05T23:54:11+09:00
CodilityのBinaryGapを競プロ未経験が解いてみた
BinaryGapとは
簡単に言うと、2進数の1と1に囲まれた0の数で最大の値を求める問題です。
例えば1000010100010であれば、1と1の間の0の個数は左から4, 1, 3となるので、ここでは4が答えとなります。正直、自信はありませんが100%のスコア判定をもらうことができました。Pythonのスペシャリストではない割には簡潔に書けたのではないかと思います。
1. Python コード
def solution(N): return len(max(str(bin(N)).replace("0b", "").split("1")[:-1]))Step. 1
str(bin(N))
で与えられた10進数を2進数に変換します。その際に文字列型へ変換も行います。Step. 2
.replace("0b", "")
二進数を文字列に変換すると最初にリテラルの0bがくっつきます、これをreplace(,)
で削除します。Step. 3
.split("1")
1で文字列を分解し、0だけの配列を作成します。Step. 4
[:-1]
でスライスし、最後の要素を削除します。これは、1000や101000のように最後の0は1で囲まれてるとは言えないためです。Step. 5
str(bin(N)).replace("0b", "").split("1")[:-1]
の時点で[0, 00000, 00, 00, 0]のような配列が出来上がります。これをmax( )
で文字数(0の数)が一番多い要素を抜き出します。この例だと00000です。Step. 6
5で00000となったので、
len()
で0の個数を数えます。この値がBinaryGapの答えとなります。Java
Javaのバージョンも書いて見ました。Javaはあまり慣れていないので、もっといい書き方があるかもしれません。基本的には上記のPythonと同じアルゴリズムです。
違う点としては与えられる引数Nが割り切れる数か判定している所とPythonではmax()
で求められた配列内の最大文字数要素を求めるのを自作している点です。
割り切れるかどうか判定した理由としては1000100101
のような文字列を1で分割した際にPythonでは["", "000", "", "00", "", "0", ""]
のような配列が帰ってくるので最後の要素を削除することで、必ず1で囲まれた0になることが保証されますが、Javaの場合は[, "000", , "00", , "0"]
のような配列になってしまい1001
のような場合に挙動が変わってしまうからです。class Solution { public int solution(int N) { String[] zeros = Integer.toBinaryString(N).split("1"); int index = zeros.length; int max = 0; /* 割り切れる数かどうかの判定 */ if (N % 2 == 0) { index = index - 1; } /* 最大値の判定 */ for (int i = 0; i < index; i++) { if (zeros[i].length() > max) { max = zeros[i].length(); } } return max; } }まとめ
今回は、アルゴリズムプログラミングに初めてトライしました。今後はCodilityの他のLessonや
Java(2019/4/6追記)などでもトライしていこうと思います.
- 投稿日:2019-04-05T17:57:26+09:00
lombokをGradleでインストールできない。
事象
Gradleに下記の2行追加して、Gradle実行したがエラーが出る。
dependencies { compile("org.springframework.boot:spring-boot-starter-web") testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('com.jayway.jsonpath:json-path') compileOnly 'org.projectlombok:lombok:1.18.6' <--追加 annotationProcessor 'org.projectlombok:lombok:1.18.6' <--追加 }エラー
Warning:<i><b>root project 'complete': Unable to resolve additional project configuration.</b> Details: org.gradle.api.artifacts.ResolveException: Could not resolve all dependencies for configuration ':runtimeClasspath'. Caused by: org.gradle.internal.resolve.ArtifactResolveException: Could not download spring-boot-starter-web.jar (org.springframework.boot:spring-boot-starter-web:2.1.3.RELEASE): No cached version available for offline mode</i>対策
どの対策が聞いたかわかりませんが、上から順にやって最後に成功しました。
Enable annotation processingにチェックを入れる。
Intellij IDEA -> Preferences -> Compiler -> Annotation ProcessorsEnable annotation processingにチェックを入れる。
File -> Other Settings -> Default Settings -> Compiler -> Annotation ProcessorsLombokプラグインをインストール
Intellij IDEA -> Preferences -> Plugins ->Browse Repositories-> Search for "Lombok"-> install plugin -> Apply and restart IDEAWork offlineにチェックを入れる。
Intellij IDEA -> Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle
- 投稿日:2019-04-05T15:25:39+09:00
因子水準の展開
因子水準を展開するサンプル
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TEMP { public static void main(String[] args){ new TEMP(); } TEMP() { TestCase1 testCase1 = new TestCase1(); List<String> testCasesString = testCase1.getTestCasesStringList(); for(String testCaseString : testCasesString) { System.out.println(testCaseString); } List<Map<String, String>> testCases = testCase1.getTestCasesMapList(); for(Map<String, String> testcase : testCases){ System.out.print(testcase.get("甲")); System.out.print(testcase.get("乙")); System.out.println(testcase.get("丙")); } } class TestCase1 extends AbsFactorLevelTypeTestCase{ void setFactorAndLevel() { factors.add(new Factor("甲").setLevels("1", "2")); factors.add(new Factor("乙").setLevels("a", "b", "c")); factors.add(new Factor("丙").setLevels("A", "B", "C")); exclude("2,b,C"); } } /** * @author maruta_r * For test-cases using factor and level. */ abstract class AbsFactorLevelTypeTestCase { protected List<Factor> factors = new ArrayList<Factor>(); private List<String> testCases; AbsFactorLevelTypeTestCase(){ setFactorAndLevel(); } /** * Specify factors and levels at subclass. * * [EXAMPLE] * void setFactorAndLevel() { * factors.add(new Factor("甲").setLevels("1", "2")); * factors.add(new Factor("乙").setLevels("a", "b", "c")); * factors.add(new Factor("丙").setLevels("A", "B", "C")); * } * */ abstract void setFactorAndLevel(); /** * Combination to be excluded from tests. * Specify the name of each levels separated by comma. * * [EXAMPLE] * exclude("1,a,B"); * exclude("2,c,A"); */ protected void exclude(String combination) { if(this.testCases == null) expandAll(); testCases.remove(combination); } /** * @return All combination of each levels separated by comma. Header included. */ public List<String> getTestCasesStringList() { if(this.testCases == null) expandAll(); return this.testCases; } /** * @return Test-cases converted Map List. Factor name is key. */ public List<Map<String, String>> getTestCasesMapList() { List<Map<String, String>> testCasesMapList = new ArrayList<Map<String, String>>(); List<String> copy = new ArrayList<String>(getTestCasesStringList()); String[] keys = null; for(String testCase : copy) { Map<String, String> map = new HashMap<String, String>(); //setting header as a keys String[] values = testCase.split(","); if(keys == null) { keys = values; continue; } for(int i = 0; i < values.length; i++) { map.put(keys[i], values[i]); } testCasesMapList.add(map); } return testCasesMapList; } private void expandAll() { List<String> result = new ArrayList<String>(); result.add(""); String header = ""; for(Factor factor : factors) { if(header.length() > 0) header += ","; header += factor.getFoctorName(); List<String> newResult = new ArrayList<String>(); for(int i = 0; i < result.size(); i++) { List<String> levels = factor.getLevels(); for(String level : levels) { String prevStr = result.get(i); if(prevStr.length() > 0) prevStr += ","; newResult.add(prevStr + level); } } result = newResult; } result.add(0, header); this.testCases = result; } } class Factor { private final String factorName; private List<String> levels = new ArrayList<String>(); public Factor(String factorName, String... args) { this.factorName = factorName; setLevels(args); } public Factor setLevels(String... args) { for(int i = 0; i < args.length; i++){ levels.add(args[i]); } return this; } public List<String> getLevels() { return this.levels; } public String getFoctorName() { return this.factorName; } }
- 投稿日:2019-04-05T12:55:20+09:00
MicronautでApache Kafkaにアクセスする
Micronaut Kafka
MicronautにApache Kafkaのサポートがあるというので、試してみることにしました。
Micronautを使って、Apache KafkaのProducerおよびConsumerを作ることができるようです。
環境
今回使ったMicronautのバージョン。
$ mn -V | Micronaut Version: 1.0.4 | JVM Version: 1.8.0_191Micronaut 1.0.4では、Apache Kafka 2.0.1に対応しているようです。
Upgrade to Kafka 2.0.1
これに合わせて、今回はApache Kafka 2.0.1をダウンロード。
$ wget http://ftp.tsukuba.wide.ad.jp/software/apache/kafka/2.0.1/kafka_2.12-2.0.1.tgz $ tar xf kafka_2.12-2.0.1.tgz $ cd kafka_2.12-2.0.1Apache KafkaのQuick Startに習い、Apache ZooKeeperとApache Kafka Brokerを起動します。
Quick Start / Start the server
## Apache Zookeeper $ bin/zookeeper-server-start.sh config/zookeeper.properties ## Apache Kafka(Broker) $ bin/kafka-server-start.sh config/server.propertiesTopicは、
my-topic
という名前で作成しました。$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic my-topic Created topic "my-topic".アプリケーションを作る
それでは、アプリケーションを作ってみます。ProducerとConsumer(ここではListenerとしていますが)用のプロジェクトを作成。
## Producer $ mn create-app --features kafka --build maven hello-kafka-producer ## Listener(Consumer) $ mn create-app --features kafka --build maven hello-kafka-listener以降、この2つのプロジェクトに対してソースコードを追加、編集していきます。
Producerを作る
では、Apache Kafka Brokerにメッセージを送信するProducerを書いてみます。
$ cd hello-kafka-producer
main
クラスは、自動生成されたまま使います。src/main/java/hello/kafka/producer/Application.java
package hello.kafka.producer; import io.micronaut.runtime.Micronaut; public class Application { public static void main(String[] args) { Micronaut.run(Application.class); } }Producerは、
@KafkaClient
アノテーションを付けたインターフェースを作成するようです。こんな感じで作成。インターフェースに対する実装クラスの作成は不要です。
src/main/java/hello/kafka/producer/MessageClient.java
package hello.kafka.producer; import io.micronaut.configuration.kafka.annotation.KafkaClient; import io.micronaut.configuration.kafka.annotation.KafkaKey; import io.micronaut.configuration.kafka.annotation.Topic; import io.reactivex.Single; @KafkaClient(acks = KafkaClient.Acknowledge.ALL) public interface MessageClient { @Topic("my-topic") Single<String> send(@KafkaKey String key, Single<String> message); }設定は、
@KafkaClient
アノテーションおよび設定ファイルで行います。
@KafkaClient
アノテーションでは、ACKの設定だけ行いました。@KafkaClient(acks = KafkaClient.Acknowledge.ALL) public interface MessageClient {設定ファイル、こちら。
src/main/resources/application.yml
--- micronaut: application: name: hello-kafka-producer --- kafka: bootstrap: servers: localhost:9092 producers: default: retries: 5
kafka.bootstrap.servers
では、Apache Kafka Brokerに対する接続設定を行います。Producerの振る舞いについては、
kafka.producers.[client-id]
で行います。
id
を指定することで、@KafkaClient
単位に設定を行うことができます。Per @KafkaClient Producer Properties
今回は特に
id
を指定していないので、default
という名前になっています。メッセージの送信は、
@Topic
アノテーションにトピック名を指定したメソッドを使って行います。@Topic("my-topic") Single<String> send(@KafkaKey String key, Single<String> message);キーを指定する場合は、
@KafkaKey
を使用します。キーを使わない場合は、指定不要です(キーの引数自体を省略できます)。また、RxJavaなど、Reactive Streamsまわりの型も使えるので、今回はこちらを利用しました。
Reactive and Non-Blocking Method Definitions
最後に、
@KafkaClient
を使う@Controller
。src/main/java/hello/kafka/producer/MessageController.java
package hello.kafka.producer; import javax.inject.Inject; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Body; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Post; import io.reactivex.Single; @Controller("/message") public class MessageController { @Inject MessageClient messageClient; @Post(value = "/{key}", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_PLAIN) public Single<String> message(String key, @Body Single<String> value) { return messageClient.send(key, value).map(v -> String.format("message [%s] sended", v)); } }ビルド。
$ ./mvnw package
これで、Producer側は完了。
Listener(Consumer)
続いて、Consumer側。
$ cd hello-kafka-listenerKafka Consumers Using @KafkaListener
Consumerは、
@KafkaListener
アノテーションを使って作成します。こちらは、class
定義になります。src/main/java/hello/kafka/listener/MessageListener.java
package hello.kafka.listener; import java.util.List; import io.micronaut.configuration.kafka.Acknowledgement; import io.micronaut.configuration.kafka.annotation.KafkaKey; import io.micronaut.configuration.kafka.annotation.KafkaListener; import io.micronaut.configuration.kafka.annotation.OffsetReset; import io.micronaut.configuration.kafka.annotation.OffsetStrategy; import io.micronaut.configuration.kafka.annotation.Topic; import io.reactivex.Single; @KafkaListener(groupId = "message-group", offsetReset = OffsetReset.EARLIEST, offsetStrategy = OffsetStrategy.DISABLED) public class MessageListener { @Topic("my-topic") public void receive(@KafkaKey String key, Single<String> message, Acknowledgement acknowledgement) { message.subscribe(m -> { System.out.printf("Received key / message = %s / %s%n", key, m); acknowledgement.ack(); }); } }
@KafkaListener
アノテーションでConsumerの設定を行い、メッセージを受け取るメソッドには@Topic
アノテーションを指定します。@KafkaListener(groupId = "message-group", offsetReset = OffsetReset.EARLIEST, offsetStrategy = OffsetStrategy.DISABLED) public class MessageListener { @Topic("my-topic") public void receive(@KafkaKey String key, Single<String> message, Acknowledgement acknowledgement) {使う型は、Reactiveなものを。
Receiving and returning Reactive Types
また、ACKを使うようにもしています。
message.subscribe(m -> { System.out.printf("Received key / message = %s / %s%n", key, m); acknowledgement.ack(); });今回は設定はBrokerへの接続先のみとしました。あと、同一ホストでProducerも立ち上げることにするので、
micronaut.server.port
は8080
以外で設定。src/main/resources/application.yml
--- micronaut: application: name: hello-kafka-listener server: port: 9080 --- kafka: bootstrap: servers: localhost:9092こちらもビルド。
$ ./mvnw package
これで、Consumer側も準備完了です。
動かしてみる
では、動作確認してみましょう。
## Producerを起動 $ java -jar target/hello-kafka-producer-0.1.jar ## Consumerを起動 $ java -jar target/hello-kafka-listener-0.1.jarProducerに適当にメッセージを放り込んでみます。
$ curl -H 'Content-Type: text/plain' localhost:8080/message/key1 -d 'value1' message [value1] sended $ curl -H 'Content-Type: text/plain' localhost:8080/message/key2 -d 'value2' message [value2] sended $ curl -H 'Content-Type: text/plain' localhost:8080/message/key3 -d 'value3' message [value3] sendedConsumer側には、こんな感じで受信したメッセージが表示されます。
Received key / message = key1 / value1 Received key / message = key2 / value2 Received key / message = key3 / value3動かせたようですね。
- 投稿日:2019-04-05T11:22:48+09:00
クラスタ構成のDBへ接続ためのJDBC URL
spring-bootでクラスタ構成のDBに接続するためのJDBC URLです。
Oracle RAC
String DB_URL= "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=" + "(LOAD_BALANCE=OFF)(FAILOVER=ON)" + "(ADDRESS=(PROTOCOL=TCP)(HOST=host1)(PORT=port1))" + "(ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=port2)))" + "(CONNECT_DATA=(SERVICE_NAME=service_name)))"上記LOAD_BALANCE=ON、FAILOVER=ONの設定を組み合わせることによって「負荷分散」と「接続フェイルオーバー」の2つの機能が有効になる。
application.properties
指定の場合、以下のように記載する。spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(LOAD_BALANCE=OFF)(FAILOVER=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=host1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=testDB))) spring.datasource.username=user spring.datasource.password=passwordAWS Aurora DBクラスタ
MariaDB JDBC ドライバーの自動フェイルオーバー機能を使用し、フェイルオーバーの状況下でマスターとレプリカを高速に切り替えられる。
JDBC URLを指定する場合、Aurora DBのクラスタエンドポイントを直接指定するか、マスターとレプリカのエンドポイントを両方指定するかの2つ方法があります。
クラスタエンドポイント指定
String DB_URL = "jdbc:mariadb:aurora//auroradbcluster.auroradbtest.com::3306/testDB";
application.properties
指定の場合、以下のように記載する。spring.datasource.url=jdbc:mariadb:aurora//auroradbcluster.auroradbtest.com::3306/testDB spring.datasource.username=user spring.datasource.password=passwordマスターとレプリカのエンドポイントを両方指定
String DB_URL = "jdbc:mariadb:aurora//rds.auroradbtest.com:3306,rds-ro.auroradbtest.com:3306/testDB";
application.properties
指定の場合、以下のように記載する。spring.datasource.url=jdbc:mariadb:aurora//rds.auroradbtest.com:3306,rds-ro.auroradbtest.com:3306/testDB spring.datasource.username=user spring.datasource.password=password
- 投稿日:2019-04-05T07:59:51+09:00
PagerViewで左右どちらにフリックしたか判定する方法
/** Touch前の座標*/ private boolean mIsPagerViewTouchDown = false; pager.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { float touchX = event.getX(); switch(event.getAction()) { case MotionEvent.ACTION_DOWN: mPreviousTouchPointX = touchX; break; case MotionEvent.ACTION_UP: float dx = touchX - mPreviousTouchPointX; // TouchDown時のタッチ座標とTouchUp時の座標を比較しどちらにフリックしたか判定 if ((Math.abs(dx) > 1)) { if (dx > 0) { Log.d(MainActivity.class.getSimpleName(), "右へフリック"+dx); } else { Log.d(MainActivity.class.getSimpleName(), "左へフリック"+dx); } } break; default: break; } mPreviousTouchPointX = touchX; return false; } });