AtCoderに登録したら解くべき精選過去問10問の類題をC++で解いてみた(その2)
前回の続き。
ABC 081 A - Placing Marbles の類題を解いていく。
ABC 079 A - Good Integer
- 4桁中上3桁または下3桁が同じ値であるか判別
- 数値を文字列として扱う
- 2桁目をcheck用にセットし、1と3桁目、または3と4桁目と同値かどうか調べる。
#include <iostream> using namespace std; int main() { string integer; char checkValue; cin >> integer; checkValue = integer[1]; if((integer[0] == checkValue && integer[2] == checkValue) || (integer[2] == checkValue && integer[3] == checkValue)) { cout << "Yes" << endl; } else { cout << "No" << endl; } return 0; }
ABC 085 A - Already 2018
- 文字列の一部を書き換える
- 意外とC++が一番簡単に書けるのでは??
#include <iostream> using namespace std; int main() { string date; cin >> date; date[3] = '8'; cout << date << endl; return 0; }
ABC 069 B - i18n
- 文字列から真ん中の文字を文字数に変換する
- C++だと文字列を配列として取れるので、文字数を取得したあと、
- 最初の文字
- 最後の文字
- 真ん中の文字数を取得
- そのあと文字列の結合を実行
#include <iostream> #include <string> using namespace std; int main() { string str,first,last,out; int strlength,middle; cin >> str; strlength = str.length(); first = str[0]; middle = strlength - 2; last = str[strlength - 1]; out = first + to_string(middle) + last; cout << out << endl; return 0; }
ABC 082 B - Two Anagrams
- 入力した2つの文字列をソート
- その際、1つ目は文字が小さい順(a to z)に、2つ目は大きい順(z to a)に並び替える・
- ソート後文字列を比較して2つ目のほうが辞書的に後の文字ならYes、逆ならNoと回答
- 全く同じ文字同士の比較が続いた場合、文字数が多いほうが辞書的に後になるので、文字数を比較したbool型のflag変数を使ってYes,Noを選択
- (変数の設定が汚いのはお許しください・・・(というより、よりよい変数の付け方を勉強しないと))
#include <iostream> #include <string> #include <algorithm> using namespace std; int main() { string anagram1,anagram2; int anagram1_size,anagram2_size; bool flag; cin >> anagram1; cin >> anagram2; anagram1_size = anagram1.length(); anagram2_size = anagram2.length(); flag = anagram1_size < anagram2_size; sort(anagram1.begin(),anagram1.end()); sort(anagram2.begin(),anagram2.end(),greater<int>()); for(int i = 0 ; i < min(anagram1_size,anagram2_size); i++) { if(anagram1[i] < anagram2[i]) { cout << "Yes" << endl; return 0; } else if (anagram1[i] > anagram2[i]) { cout << "No" << endl; return 0; } } if(flag) { cout << "Yes" << endl; } else { cout << "No" << endl; } return 0; }
AtCoderに登録したら解くべき精選過去問10問の類題をC++で解いてみた(その1)
C, C++の勉強を兼ねて、
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~
をやっていたのですが、10問終えたので、類題を解いていこうと思います。
まずは、ABC 086 A - Product の類題から。
- 倍数判定
- 3つの数字から3桁の数字を作り出して、4で割り切れるか判定
#include <iostream> using namespace std; int main() { int r,g,b; int integer; cin >> r >> g >> b; r *= 100; g *= 10; integer = r + g + b; if(integer % 4 == 0) { cout << "YES" << endl; } else { cout << "NO" << endl; } return 0; }
- 余り計算
- 500で割った時の余り(=500以下の数値)を出して、それがcoinsの数以下かどうか判定
#include <iostream> using namespace std; int main() { int yen,coins; int remain; cin >> yen; cin >> coins; remain = yen % 500; if(remain <= coins) { cout << "Yes" << endl; } else { cout << "No" << endl; } return 0; }
- 小数点以下の切り上げ
- キャストを使いながら、小数点以下の値がある場合に1繰り上げるように処理してみた
#include <iostream> using namespace std; int main() { int a,b,int_cast_avg; double avg; cin >> a >> b; avg = (a + b) / 2.0; int_cast_avg = (int)avg; if(int_cast_avg < avg) { int_cast_avg++; } cout << int_cast_avg << endl; return 0; }
エンジニアのためのマインドフルネス(という名の自分がやっていること)
TL,DR
マインドフルネスは時間の浪費じゃなくて投資。
My Spec
- 身長: 166cmをいったりきたり
- 体重: 60台半ばくらい
- BMI: 2じゅう・・・(ry
新しく始めたこと
- 運動(筋トレ、ランニング)
- 集中力を鍛える(瞑想、集中力カード)
- 姿勢
きっかけ
- 今年の正月に食べ過ぎで目に見えて太った。
- 去年秋の健康診断の結果が悪かった。
- 集中力が切れやすくなっていった(眠気、気づいたらネットサーフィンしてる)
運動
準備
実践
- 起床後
- お昼休み
- ジムでランニング(20分)、または図書館の行き帰りにウォーキング(40分)
集中力
瞑想
- 姿勢を正す(椅子に座ってても、あぐらをかいてても良い)
- 深呼吸をする(4秒吸って、4秒吐くくらいの気持ちで)
- 心を無にする(頭に何か浮かんだら浮かんだ自分を客観視する・20分~30分くらい)
集中力カード
完全にこの本の受け売り。
- URLにある黄色と青色でダイヤのような画像を使う
- 深呼吸(3秒吸う、2秒息を止める、6秒でゆっくり吐く) + 画像の中心点(黄色い丸点)を20秒くらいじっとみつめる
- 20秒後、目をつぶると見ていたダイヤ型の画像が浮かび上がるので、それが消えないようにする
姿勢
変化したこと
朝の目覚め
- どれだけ早く寝ても朝起きるのがしんどかったのに、今では朝の目覚めが抜群によくなった。(というか朝になれば勝手に目覚める)
- おかげで朝の貴重な時間を使うことができるように。
集中力
- 何をするにも集中がしやすくなった
- 読書のスピード向上
- 2~300Pくらいのビジネス書、基礎レベルの技術書なら2時間かからないくらい
- 英語の技術書、MOOCのような動画講義もある程度すらすら読み聞きできるようになった(昔は少し読むと頭が痛くなっていた)
- 仕事をダラダラやることがなくなった
- 仕事の生産性があがった(主観的)
- 読書のスピード向上
ポジティブシンキング
- 気持ちがある程度前向きになった
- クヨクヨ悩むことも少なくなり即断で動けるように
変わらないこと
た、体重、、、
- まだ1ヶ月くらいしかたっていないのでそんなもんかなと
- 落ち込むときもあるけど、「やらないよりは遥かにマシ」と言い続けている
- (筋肉が増えて、体脂肪が減っていることをただただ祈っている)
気をつけていること
無理をしない
- しんどい時はやらない
- 朝早い時、いつもより体調が悪そうな時は少し早めに切り上げる
毎日やる
- 週2で1時間より、毎日最低10分を心がけている(習慣化させるため)
これからの予定
最後に
これってマインドフルネスなのか?
Ubuntu16.04にCDH5を入れる
CDH5をインストールするを読んで、Ubuntuでやろうとしたら思いの外つまづいたので、備忘録代わりに残しておきます。
(今更こんな方法でHadoop入れる人いないと思うけど。。。)
環境
Javaのインストール
ひとまず、java8を先に入れて、PATHを通しておきます。
sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get -y install oracle-java8-installer cat << EOF >> ~/.bashrc JAVA_HOME=/usr/lib/jvm/java-8-oracle PATH=$PATH:$JAVA_HOME/bin export JAVA_HOME export PATH EOF source ~/.bashrc
Hadoopのリポジトリ登録
ここでおおきく躓いた。。。
まず、そもそもリポジトリの概念がCentとUbuntuで異なるので、Ubuntu用のファイルをとってこないと行けない。
# trustyはUbuntu14.04だけど、16.05用のディレクトリがないのでこっちから落としてくる
sudo wget https://archive.cloudera.com/cdh5/one-click-install/trusty/amd64/cdh5-repository_1.0_all.deb
その後、debパッケージを開く
sudo dpkg -i cdh5-repository_1.0_all.deb
sudo curl -s https://archive.cloudera.com/cdh5/ubuntu/trusty/amd64/cdh/archive.key |
sudo apt-key add -
これで準備は完了。。。と思いきや、、、ここでまた一つ問題が・・・
インストールするバージョンを指定する
というのも、このままなにもせずに素直にapt-getすると最新版のCDHが入ってしまう。
今回は都合によりバージョン5.12に指定したいので、
/etc/apt/sources.list.d配下のcloudera-cdh5.listファイルを修正する
cd /etc/apt/sources.list.d cp cloudera-cdh5.list cloudera-cdh5.list.orig cat << EOF > cloudera-cdh5.list deb [arch=amd64] https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh xenial-cdh5.12 contrib deb-src https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh xenial-cdh5.12 contrib EOF
ポイントは指定するURLで
https://archive.cloudera.com/cdh5/ubuntu/<Ubuntuのバージョン>/amd64/cdh <Ubuntuのバージョン> - <インストールするCDHのバージョン>
みたいにする。
今回は、
+ Ubuntu : 16.04(xenial)
+ Hadoop : CDH5.12
だったので上のような書き方になった。
ちなみに、書き方を見たい場合は、
https://archive.cloudera.com/cdh5/ubuntu/
例: https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh/conf/distrobutionsの一部
Origin: Cloudera Label: Cloudera Codename: xenial-cdh5.11.1 Version: 16.04 Architectures: amd64 source Components: contrib Description: Cloudera nightly packages for xenial SignWith: 02A818DD Origin: Cloudera Label: Cloudera Codename: xenial-cdh5.12.0 Version: 16.04 Architectures: amd64 source Components: contrib Description: Cloudera nightly packages for xenial SignWith: 02A818DD Origin: Cloudera Label: Cloudera Codename: xenial-cdh5.12 Version: 16.04 Architectures: amd64 source Components: contrib Description: Cloudera nightly packages for xenial SignWith: 02A818DD
Hadoopインストール&起動
あとは素直にHadoopを入れて動かすだけ。
sudo apt update sudo apt-get install -y hadoop-conf-pseudo sudo -u hdfs hdfs namenode -format sudo systemctl start hadoop-hdfs-namenode hadoop-hdfs-datanode hadoop-hdfs-secondarynamenode sudo /usr/lib/hadoop/libexec/init-hdfs.sh sudo systemctl restart hadoop-hdfs-namenode hadoop-hdfs-datanode hadoop-hdfs-secondarynamenode sudo systemctl start hadoop-yarn-resourcemanager hadoop-yarn-nodemanager
結論
Cloudera ManagerとCloudera Directorは正義。
LDAP基本の基本解説という名のメモ(初心者向け)
久しぶりに仕事でLDAPをいじろうと思ったら、すっかり言葉や仕組みを忘れてしまっていたので、再勉強のついでにLDAPのことをメモ代わりに書き残しておきます。
参考書はこちら
入門LDAP/OpenLDAP ディレクトリサービス導入・運用ガイド 第3版
What is LDAP
Lightweight directory access protocolの略称。
その名の通り、プロトコル。(FTPとかHTTPと同じ類)
もともとあったDAPというサービスを軽量化させて一般的に使えるようにしたもの。
ユーザーやパスワード等を管理するために使われる。(RDBではない)
用途
- 社内のITサービスにおけるユーザー管理
- ユーザーにまつわる認証、認可関連
LDAPにおけるデータ構造
エントリ
DBでいうところのテーブルのようなもの。
組織エントリとか、在庫エントリとか。
基本的にKey/Value形式のような形で、属性名/属性値を設定する。
属性名 | 属性値 |
---|---|
名前 | 山田一郎 |
住所 | 大阪府〇〇 |
電話番号 | △△△△ |
オブジェクトクラス
DBでいうカラムの定義。
各属性に対して、どんな情報を入れるのかを定義しておく。
例えば電話番号に文字列が入るとおかしいなどバリデーションができる。(属性構文)
これらをまとめたものをスキーマと呼ぶ。
DIT(ディレクトリインフォメーションツリー)
基本的にLDAPでは各ユーザーを階層構造で定義しておき、芋づる式でユーザーを検索する。
その階層を定義するのがDITとなる。
例:
◯◯会社の△△部□□課の山田さんというユーザーは、
+ 会社
+ 部
+ 課
という3つの階層が定義されており、その中で管理されている。
(ここでいう△△部とか□□課は他の部や課と区別するということでRDN(Relative Distinguished Name)と呼ばれる)
- DITでよく出る用語 |用語|概要| |----|----| |dn|識別名| |objectClass|そのまま| |dc|ドメインを構成する要素| |o|組織名| |ou|組織単位| |cn|名称|
さっきの例をDITの用語で表現すると、
DN: cn=山田さん,ou=□□課,ou=△△部,dc=◯◯会社
みたいになる(はず)
※上記参考書のp26の図がすごくイメージがしやすくなります。
LDAPを使ったアクセス認証
LDAP使用時におけるユーザーのアクセス認証については、
+ 各dnにたいしてパスワードを設定する
+ SASL等のSSOと連携
+ Linuxのユーザー権限と組み合わせ
が可能。
LDAPを使ったユーザー検索
ユーザー検索では、
+ どの階層に属しているユーザーを検索するか(base)
+ 指定した階層からどこまで掘り下げて検索するか(one,child)
を設定する。
またフィルタを設定することで検索から必要なユーザーだけ抽出も可能。
LDAP更新
LDAPでは追加、更新、削除ができるが、これらはLDIFと呼ばれるフォーマットで設定する
とりあえずここまで。
次回くらいに簡単に構築したものを載せてみようかな。
Lambda用にテンポラリーアクセスキーを作成する(あくまで試行錯誤の過程)
以前期限付きURLをLambdaで作成する方法を紹介しました。
そこで最大7日間まで設定できると高をくくったのですが、
いざ使ってみるとものの数時間で、
This token has expired
的なエラーが返ってきます。。。
念のため、何度か確認したのですが、設定した値より前にダメになりました。
何か問題がないかと確認したところ、以下の仕様っぽいです。
- Lambdaで期限付きURLを発行するとテンポラリのアクセスキーが生成される。
- 期限より前にテンポラリーアクセスキーの期限がterminateされるとURLも使えなくなる。
これは面倒ですね。。。
であれば、以下のように、
import boto3 from boto3.session import Session def lambda_handler(event, context): BUCKET = '<バケット>' KEY = '<ファイル名(パスを含む)>' #持っているアクセスキーとシークレットキーを指定 session = Session(aws_access_key_id = '<アクセスキー>', aws_secret_access_key = '<シークレットキー>', region_name = 'ap-northeast-1') s3 = session.client('s3') url = s3.generate_presigned_url( ClientMethod = 'get_object', Params = {'Bucket' : BUCKET, 'Key' : KEY}, ExpiresIn = 6048000, HttpMethod = 'GET' ) print(url)
とすれば問題ないのですが、これだとアクセスキーが完全に露出してしまうのでセキュリティ的に怖いです。
なので、一時的なアクセスキーを作成する方法をさくっと調べてみました。
アクセスキーの作り方 + assumeroleのポリシーを作成 + ポリシーをLambda実行するロールに割り当て + boto3でassumeroleを実行(今回はLambdaでやってみる)
assumeroleポリシーを作成
まずはIAMに移動し、ポリシーで以下のようなポリシーを作成します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "<sidの値>", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::<数字>:role/<ロール名>" } ] }
ポリシーをLambda実行するロールに割り当て
これはそのままIAMのロールにてポリシーを割り当てを設定すればよいです。
boto3でassumeroleを実行
今回はLambdaで以下のようなプログラムを作ってみました。
import boto3 def lambda_handler(event,context): sts = boto3.client('sts') result = sts.assume_role( RoleArn = '<assumeポリシーで設定したロールのARN>', RoleSessionName = '<適当なセッション名>', DurationSeconds=3600 ) print(result)
これをテストで動かしてみると結果にアクセスキーが生成されます。
課題
しかし、上記プログラムでDurationSecondsの値を3600(1時間)以上に設定するとエラーが発生。
"errorMessage": "An error occurred (ValidationError) when calling the AssumeRole operation: The requested DurationSeconds exceeds the MaxSessionDuration set for this role.",
boto3のリファレンスを見てみると、、、
- DurationSecondsの最大値は3600
うーんこれは困りましたね。。。
文章ではSessionSecondsの設定で12時間まで引き上げられるっぽいのですが、この関数のパラメータとしては渡せないので、どうしていくかこれから考えてみます。
起動させるたびにIPが変わって鬱陶しいあれをなるべくお金をかけずに解決する
前ふり
AWS等クラウドでサーバを立てる時に気になるお金。
なるべく課金を減らすために必要なときだけ立てて、いらなければ落とすなんてことをしますよね。
でも落とした後に起動するとやっかいなのがIPアドレスの変更。
毎回毎回アドレスが変わってしまうとssh config等の設定を変えないといけなかったりして面倒なんですよね。
かといってElasticなIPを使うとそれでもお金がかかってしまうので嫌だ。。。
というわけで、なるべくお金をかけずにかつ設定をなるべく変えないでサーバを扱う方法を紹介します。
※今回の例はあくまで検証や遊びでサーバを立てて使う人用の方法です。本番システムでの利用は推奨しません。
やること
- VPCを作成
- パブリックサブネットとプライベートサブネットを立てる
- インターネットからパブリックサブネットにアクセスさせる設定
- パブリックサブネットに踏み台サーバを立てる
- プライベートサブネットに検証サーバを立てる
- ssh configで踏み台経由でサーバにアクセスする設定を行う
- ssh <設定名>でいつでもアクセスできるWHYYYYYYY
やっていることのほとんどはAWSEC2のデザインパターンとかでよくみるやつです。
VPCの作成
まずは、VPCを作成します。
AWSのユーザーコンソールからVPCに移動
設定項目 | 設定値 |
---|---|
名前タグ | 適当な名前で |
IPv4 CIDRブロック | なんでもいいけどVPCにいっぱいサーバを立てるなら10.0.0.0/16が順当かと |
IPv6 CIDRブロック | ブロックはなしで |
テナンシー | デフォルトでOK |
パブリックサブネットとプライベートサブネットを立てる
続いてサブネットを作ります。
ユーザーコンソールからVPC -> サブネットに移動。
サブネットではインターネット経由でアクセスできるパブリックサブネットとプライベートサブネットを設定します。
- パブリックサブネット側
設定項目 | 設定値 |
---|---|
名前タグ | 適当な名前で |
VPC | さっき作成したVPC名を指定 |
アベイラビリティーゾーン | 今回は特に指定なしでOK |
IPv4 CIDRブロック | VPCで設定したブロック内で範囲を指定。今回は10.0.1.0/24としておく。 |
- プライベートサブネット側
設定項目 | 設定値 |
---|---|
名前タグ | 適当な名前で |
VPC | さっき作成したVPC名を指定 |
アベイラビリティーゾーン | 今回は特に指定なしでOK |
IPv4 CIDRブロック | VPCで設定したブロック内で範囲を指定。今回は10.0.2.0/24としておく。 |
インターネットからパブリックサブネットにアクセスさせる設定
ここは大事なところ。
2つサブネットを作成した後に、パブリックサブネットのみ選択して、サブネットのアクション-> 自動割り当てIPの設定変更 に飛ぶ
そこで、 パブリックIPv4アドレスの自動割り当てを有効にする にチェック。
これをやっとかないと踏み台サーバ立てても外部からサーバにアクセスするための外部IPを発行してくれません。
次にやるのはインターネットとパブリックサブネットをつなぐゲートウェイ(窓口みたいなもの)の設定
- VPC -> インターネットゲートウェイに移動
- インターネットゲートウェイの作成を押して文字通り作成(名前は適当に)
- さっき作ったゲートウェイを選択して、 アクション->VPCのアタッチを選択
- VPCでさっき作ったVPCを選択してアタッチ
- VPC -> ルートテーブルに移動
- 作ったVPCに紐づくルートテーブルを選択。
- 下部にあるルートタブを選択して編集。
- 別のルートを追加を選択。以下のように設定
送信先 | ターゲット |
---|---|
0.0.0.0/0 | さっき作ったゲートウェイの名前 |
これでできました。
パブリックサブネットに踏み台サーバを立てる
ここから踏み台サーバを立てます。
サーバの立て方は基本的な方法と同じなので割愛。
一般的な立て方と違うのは以下の点。
+ インスタンスのタイプはt2.nano(踏み台用途なので and 24時間稼働を想定してなるべくお金がかからないように)
+ インスタンスの詳細の設定にて
+ ネットワーク -> 作ったVPCの名前
+ サブネット -> パブリックサブネットの名前
プライベートサブネットに検証サーバを立てる
今度はプライベート側に実際に使用するサーバを立てます。
こちらも基本的な立て方は同じ。
変更点は以下の点
+ インスタンスの詳細の設定にて
+ ネットワーク -> 作ったVPCの名前
+ サブネット -> プライベートサブネットの名前
+ セキュリティグループは基本的に全開放でも問題ないが、気にされる方は必要なポートをパブリックサブネットのIPに指定するとよし。
ssh configで踏み台経由でサーバにアクセスする設定を行う
サーバが立てられたので、sshでつなぐ設定をします。 今回はmacを想定し、macの.ssh/configに設定をします。
# ~/.ssh/config Host humidai HostName <踏み台サーバのパブリックIP> User ubuntu #サーバによって変化 Port 22 #sshポート GatewayPorts yes IdentityFile ローカルマシン内で踏み台サーバの公開鍵が置いてある場所 Host server HostName <10.0.2.xxとなるIP> User ec2-user #サーバによって変化 Port 22 GatewayPorts yes ProxyCommand ssh -CW %h:%p humidai #humidaiは上記設定したHostの名前を指定 IdentityFile ローカルマシン内で検証サーバの公開鍵が置いてある場所 # ProxtCommandが踏み台サーバ経由でsshサクセスさせるためのコマンド
この設定をした後、
ssh server
とコマンドを入力すると、踏み台経由でアクセスできます。
しかも、検証サーバを一旦落として再度あげてもプライベートIPは変わらないので、そのままsshコマンドで入れます。
また、ポートフォワーディングしたい場合は、
# ~/.ssh/config #踏み台側 LocalForward 5432 localhost:5432 LocalForward 8080 localhost:8080 #サーバ側 LocalForward 5432 <サーバのプライベートIP>:5432 LocalForward 8080 <サーバーのプライベートIP>:8080
と設定すればOK
懸念事項
- この構成にすると、サーバ側からインターネットにつなぐことができないので、wgetとかでファイルを落としたりすることはできません。
これについては別途NATインスタンスとかNATゲートウェイが必要になるのですが、いずれにしてもお金がかかる。。。。
なので、しょっちゅうインターネットにアクセスしないのであれば、ローカルマシンに対象ファイルを落としてscpコマンドで移動がよいかなと。
実際scpコマンドで移動させる場合でも
scp <移動させるファイル> server:/home/ec2-user
みたいな感じで簡単に移動できます。
- この構成は踏み台サーバは常時稼働を想定しています。踏み台サーバはt2.nanoの最小構成なので、
$0.0058 /1 時間 -> 500円くらい/1ヶ月
が必要経費になります。
ただ、毎回毎回IPアドレスを変える手間とか、めんどくさくてサーバをずっと起動させることによる課金等を考えると決して高い値段ではないかなと。
終わりに
今回は最近良くやるAWSでの検証サーバ構築用のシステムを紹介しました。
上述したように、この構成は本番構成でもやるような部分も含まれていますので、特にAWS初心者の方はぜひチャレンジしてみるといいかもしれません。
ホントの最後に
間違いとか、わからないとこがあればコメントとかしていただければ!!