AtCoderに登録したら解くべき精選過去問10問の類題をC++で解いてみた(その3)
前回の続き。
ABC 081 B - Shift Onlyの類題を解きます。
ABC 068 B - Break Number
- 指定された数値を1ずつループで処理しながら2で割り切れる数をもとめる。
- max値とmaxカウンターを用意しておいて、そのカウンター以上割り切れる回数が多い数がでてきたら更新する。
#include <iostream> using namespace std; int main() { int i,j,input,counter; int max = 0; int maxcounter = 0; cin >> input; for(i = 1;i <= input; i++) { j = i; counter = 0; while(j > 1) { if(j % 2 == 0) { j /= 2; counter++; }else { break; } } if(counter >= maxcounter) { max = i; maxcounter = counter; } } cout << max << endl; return 0; }
ABC 073 B - Theater
- 団体客毎にループで処理
- 各ループ毎の人数を足し算していって、結果を出力
#include <iostream> using namespace std; int main() { int i,j,first,last,groups,counter,num_people; cin >> groups; for(i = 1; i <= groups; i++) { cin >> first >> last; counter += last - first + 1; } cout << counter << endl; return 0; }
ABC 072 B - OddString
- 入力された中から奇数番の文字のみ取得
- C++だとStringを配列としてもてるので、配列の番号で偶数番(配列は0からはじまるので)を文字列結合させる
#include <iostream> #include <string> using namespace std; int main() { string input; string output = ""; int i; cin >> input; for(i = 0; i < input.length(); i+=2) { output += input[i]; } cout << output << endl; return 0; }
ABC 053 B - A to Z String
- 文字列の中からAを見つけて、そこからZまでの長さの最大値をもとめる
- 何も考えずにAを見つけたら文字列の最後まで調べてZを見つけるなんてことをやったら時間オーバーになった
- よく考えれば最初にAを見つけたらその後にAがきたとしてもそれが最大の長さになるわけじゃないので、見つけ次第Zまでの長さを求めた後、break文を挟んだら通った。
#include <iostream> #include <string> using namespace std; int main() { string input; int i,j; int stringlength = 0; cin >> input; for(i = 0; i < input.length(); i++) { if(input[i] == 'A'){ for(j = i; j < input.length(); j++) { if(input[j] == 'Z') { stringlength = j - i + 1; } } break; } } cout << stringlength << endl; return 0; }
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時間まで引き上げられるっぽいのですが、この関数のパラメータとしては渡せないので、どうしていくかこれから考えてみます。