投稿

BinarySearch(二分探索)を実装するときにPython3とJavaでは書き方が異なる話。

イメージ
二分探索の書き方 なぜこのような書き方をしなければならないのか? 二分探索の書き方 を実装するときにPythonでは中間値の宣言を mid = ( left + right ) // 2 で済みますが、Javaでは以下のような書き方をする必要があります。 mid = left + ( right - left ) / 2 ; ちなみにこれはC++にも当てはまります。 mid = left + ( right - left ) / 2 ; なぜこのような書き方をしなければならないのか? 何故このような書き方をしなければならないかというと、仮に left + right の値が 2^31-1 よりも大きければ、オーバーフローして負の値になるからです。 例えば、Javaでそのような長さの配列が与えられ、読み込んでしまった場合には例外として ArrayIndexOutOfBoundsException が発生します。 C++の場合には不正な書き込みが発生し、メモリ破壊などに繋がることもあります。 Pythonでは整数値にはオーバーフローがなく、オーバーフローを意識するような処理を書かなくても処理を行うため、とてつもなく大きな値でも計算時の精度は落ちません。 二分探索を書くときには気をつけようってことで一応メモを残しておきます。

int[26],int[128],int[256]の話。

イメージ
LeetCodeのLongest Substring Without Repeating Charactersにて LeetCodeのLongest Substring Without Repeating Charactersにて Sliding Windowアルゴリズムを実装している例を写経している時に int [ ] chars = new int [ 26 ] ; という表現を見つけたので何故このような宣言をしているかを調べた。 結果としては単純にアルファベットの数分の領域を確保するために行なっているよう。 他にも int [ ] chars = new int [ 128 ] ; や、 int [ ] chars = new int [ 256 ] ; が存在するが、これらは int[128] は ASCII用、 int[256] は拡張 ASCII用ということだった。 ASCIIは7ビット、拡張ASCIIは8ビットを使用していることを考えれば容易に思いつくはずなのに、調べないと分からなかったので記事にしました。 多分また調べるんだろうなぁ…

JavaのEnumについて

イメージ
この記事を書いた理由 この記事を書いた理由 最近買った Elements of Programming Interviews in Java: The Insiders’ Guide にて以下のようなコードがあったため。 これ自体は書いてあるコメントの通り配列 A と pivotIndex を引数に貰い、最初に pivotIndex より小さな値、その後に pivotIndex と同じ値、その後に pivotIndex よりも大きな値の順に配列を並び替えるというアルゴリズム。 Enum に馴染みが余りなかったため気になって調べた。 列挙型といい、使うと定数を宣言するのに読みやすいコードになるらしい。 そしてその後にちょくちょく登場する ordinal 。これは enum 型から列挙した内容の順番を取り出し、比較に使えるというもの。 定数を列挙できるのは便利なように見えるので使えたら使いたい。 でも使わないんだろうなぁ・・・ そういえばこの本はKindle版で売っていたので買いました。やっぱり電子書籍だと自炊しなくて良いから楽ですね。

数値の配列が与えられた時、配列の最初に偶数が現れるよう並び替える

イメージ
出典 Elements of Programming Interviews in Python: The Insiders’ Guide (English Edition) 問題 数値の入った配列が渡されます。 偶数の値が最初に現れるように配列の値を並べ替えなければしてください。 なお、追加で配列を用意してはなりません。 解法 # List[int] -> None def even_odd ( A ) : next_even , next_odd = 0 , len ( A ) - 1 while next_even < next_odd : if A [ next_even ] % 2 == 0 : next_even += 1 else : A [ next_even ] , A [ next_odd ] = A [ next_odd ] , A [ next_even ] next_odd -= 1 # Time Complexity O(N) # The additional space complexity O(1) 値が2で割り切れる時はイテレーションのインデックスを後ろにずらし、そうでない場合には入れ替え(スワップ)と後ろのインデックスを前にずらすことで比較的容易に実装が出来ます。

姿勢の悪さを改善するべくサンワサプライのキーボードとダイソーの300円マウスを買った

イメージ
仕事の時に余りにも前傾姿勢 すぎたので。 2022年は姿勢を美しくしようということでディスプレイを覗き込まなくても良い環境を作ろうと思いました。 買ったのは サンワサプライ Bluetoothキーボード SKB-BT25BK と ダイソーでたまたま売っていた300円のゲーミングマウス風マウス。 この記事もそれらを使って書いていますが中々快適。 打鍵感もいいし。 やはり外付けモニターのみだと視線が上がって覗き込まなくて良い。 当初は昇降デスクを買いたいなと思っていたけれどもそんなに必要か?という貧乏性からくるお金使いたくない欲が爆発してその案は四散した。 後捨てるのめんどくさそう。偏見かもしれないけど。 次に考えたのがPCスタンド。 でもなんか側から見たらちょっと間抜けに見えるのでボツ。 ということで貧乏性と見栄えを気にして2000円くらいのキーボードと330円のマウスでなんとかしました。 ボーナス入ったらHHKBとか買おうかと思っていたけどそんな欲も消し飛ぶくらいには落ち着いています。なんか不思議。

Pythonの二次元配列から最も大きい値を取得する

イメージ
最長部分共通問題を解いているときに 最長部分共通問題を解いているときに 気になったので調べてみた。 最長共通部分列(Common Longest Subsequence) の問題を解いている最中にこの記事を読んでいて、あれ?これだと最長の共通部分が何文字分あるのか返せてないな、でも二次元配列ってどう返すんだっけ? となったので調査。 ちなみに max(dp) や max(max(dp)) では返せませんでした。 結論としては ここ が参考になった。 大人しく従ったら上手く返せたのでメモがてら記事を書いておく。 max ( list ( map ( lambda x : max ( x ) , dp ) ) ) これで返すか、 from itertools import chain list ( chain ( * a ) ) max ( chain ( * a ) ) こう返すかの二択っぽい。 ちなみにつまづいていた最長部分共通問題は これ で、ソースコード(メモ化とDPを試した)は ここ 。 時間がある人はぜひ解いてみてください。

OracleのNVARCHAR2は2バイト

イメージ
 という話。 そもそも何でそんな話に? 文字列をバイトで区切って処理を行おうとした時の話。 これOracleから取り出すときにsubstrb関数を使ってバイト数を指定すれば楽じゃね? という考えに至り、実際にそれを試したがテストを行った時にあらびっくり。 半角も全角も同じ桁数で区切られているじゃありませんか。 これはまずい。半角1バイト全角2バイトじゃないの!?という考えを持っていたのでパニクった。 ってことでひとまず原因を調べたところ、タイトルの内容に辿り着きました。 固定バイト数で考えられるからプラスに働くこともあるが、今回は知らないが故に時間を無駄にかけてしまった・・・ NVARCHAR2、便利なので何でもかんでもNVARCHAR2に設定していいわけではない、という教訓を得ました。 取り方を知っていれば一発で解決じゃん、という考えもあるのでコードをメモ的に取っておくと良いかも。やるかは分からない。

JavaのindexOf関数はナイーブ法で実装されているらしい

イメージ
indexOf関数とは 実際のソースを見よう ナイーブ法ってなんぞや indexOf関数とは ドキュメント はここ。 indexOf の細かい使い方は説明はしないが、簡単にいうと二つの文字列を比較して重複する箇所がある場合にその開始部分のインデックスを返すというもの。 実際のソースを見よう どのように実装されているのかが気になったので jdkの中に存在するsrc.zipを解凍して確認してみることに。 public int indexOf ( String str ) { return indexOf ( str , 0 ) ; } public int indexOf ( String str , int fromIndex ) { return indexOf ( value , 0 , value . length , str . value , 0 , str . value . length , fromIndex ) ; } static int indexOf ( char [ ] source , int sourceOffset , int sourceCount , char [ ] target , int targetOffset , int targetCount , int fromIndex ) { if ( fromIndex >= sourceCount ) { return ( targetCount == 0 ? sourceCount : - 1 ) ; } if ( fromIndex < 0 ) { fromIndex = 0 ; } if ( targetCount == 0 ) { return fromIndex ; } char

ゼロから始めるLeetCode Day42「2. Add Two Numbers」

イメージ
#概要 海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。 その対策としてLeetCodeなるサイトで対策を行うようだ。 早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイト。 せっかくだし人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。 Leetcode ゼロから始めるLeetCode 目次 前回 ゼロから始めるLeetCode Day41「394. Decode String」 今はTop 100 Liked QuestionsのMediumを解いています。 Easyは全て解いたので気になる方は目次の方へどうぞ。 Twitter やってます。 問題 2. Add Two Numbers 難易度はMedium。 Top 100 Liked Questionsからの抜粋です。 空ではない連結リストを与えられるので与えられた数字をそれぞれ桁ごとに足していき、反転させて返すようなアルゴリズムを設計してください、というものです。 Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807. 解法 # Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution : def addTwoNumbers ( self , l1 : ListNode , l2 : ListNode ) - > ListNode : tempsum = 0 root = cur = ListNode ( 0 )

Javaでの文字列結合には気をつけよう!という話

イメージ
非効率はやめよう ということでよくあるコードとして紹介されていた内容をそのままメモ。 使えるようにしておく。 public class concat { // ループごとにStringBuilderオブジェクトを生成し、2回のappend処理を行う。非効率になる可能性高し。 static String concatTest1 ( String [ ] array ) { String result = "" ; for ( String s : array ) { result += s ; // +=演算で文字列結合 } return result ; } // 効率よし。ただしイミュータブルなStringを使わないことでバグが出やすくなるためそこの安全性を取るか効率を取るかはご自由に。 static String concatTest2 ( String [ ] array ) { StringBuilder result = new StringBuilder ( ) ; for ( String s : array ) { result . append ( s ) ; // +=演算で文字列結合 } return result . toString ( ) ; } }

Javaの ? true a:b;←これ何よと思ったので

イメージ
Javaの ? true a:b;←これ何よと思ったので Javaの ? true a:b;←これ何よと思ったので 発端はLeetCode。 Javaで書くか〜と思い、書いた後に Solution で使われていたこれ。 public ListNode addTwoNumbers ( ListNode l1 , ListNode l2 ) { ListNode dummyHead = new ListNode ( 0 ) ; ListNode p = l1 , q = l2 , curr = dummyHead ; int carry = 0 ; while ( p != null || q != null ) { int x = ( p != null ) ? p . val : 0 ; // ここ int y = ( q != null ) ? q . val : 0 ; int sum = carry + x + y ; carry = sum / 10 ; curr . next = new ListNode ( sum % 10 ) ; curr = curr . next ; if ( p != null ) p = p . next ; if ( q != null ) q = q . next ; } if ( carry > 0 ) { curr . next = new ListNode ( carry ) ; } return dummyHead . next ; } ということで調べた。 三項演算子だった。 ? true a : b ; 評価式がtrueの場合、 : の左側(この場合は a )が返る、ということで、値を返すだけならば書きやすくなる。