Create 300. Longest Increasing Subsequence.md#50
Conversation
There was a problem hiding this comment.
num_subsequences という変数名は、サブシーケンスの数というニュアンスに感じました。 最大の増加部分列の長さという意味に近づけるため、 max_subsequence_lengths または max_lengthsはいかがでしょうか?
There was a problem hiding this comment.
@nodchip さん
ありがとうございます。max_subsequence_lengthsが個人的に良いと思いました。また、numは少しニュアンスが異なるのも同意です。
There was a problem hiding this comment.
アルゴリズムの形は理解しているもの、それがなぜ正しく動いているのか、仕組みを理解していないような印象を受けました。念のため、なぜ正しく動いているか、仕組みを説明してみていただけますか?特に、リストのインデックスと、その位置の値がどのような関係性を持つかに着目して説明するとよいと思います。
また、仕組みを理解しているのであれば、 increasing_subsequence に代入される各要素が、 increasing_subsequence という変数名で表されるものとは異なるということが分かると思います。適切な名前を付け直してみていただけますか?
There was a problem hiding this comment.
ありがとうございます。
少し質問の理解に自信がなく("アルゴリズムの形"と"なぜ正しく動くか"の違い)、検討違いな答えになっていたらご指摘お願い致します。
リストのインデックスとその位置の値に関しては、リストの各インデックスの値は、increasing subsequenceの末尾として考えられる最小値、という理解です。
ロジック全体として、各値を元のリスト(nums)の順番通りに値: MAX_INTで初期化されたリストに入れて行った際、
- ある値nが部分列の末尾候補より小さいものがある:
その位置にnを代入し、より小さい値で更新を行う。これで、より長いincreasing subsequenceを検討することが可能。 - ある値nが部分列のどの末尾候補より大きい:
まだ更新されていないMAX_INTがある位置を返すため、新たな増加部分列(長さが1つ伸びたもの)の候補として、nを記録する。
これを繰り返し、最終的に部分配列の最初のMAX_INTの位置(numsの値で更新された部分長さ + 1)が最終的に作ることが可能な最大のincresing_subsequenceの長さとなります。
ここまでを言語化して、increasing_subsequenceの変数名のほか候補としては、
min_end_values , 'min_last_vals'などかなと思いました。
間違っている部分もあるかもしれませんが、ご一読いただけますと幸いです。
There was a problem hiding this comment.
前半部分のなぜ正しく動くかの部分は正しく理解できているように思いました。
後半部分の変数名については、悪くないように思いました。インデックスと、その値の対応関係が、より明確に変数名に表現されているとよいと感じました。例えば、リスト自体を 1-based に変更したうえで、 length_to_min_last_values としてしまうなどを考えました。
There was a problem hiding this comment.
ありがとうございます、よかったです。
リスト自体を 1-based に変更したうえで、 length_to_min_last_valuesも良いなと思いました。また、appendしていく方法で、length_to_min_last_valuesと名前つけるのが一番直感的に変数名と合うのかなとも思いました。
There was a problem hiding this comment.
空のリストから始め、 bisect_left() の結果が len(increasing_subsequence) だった場合、末尾に要素を追加するという方法もあります。最後は return len(increasing_subsequence) することになります。入力によってはこちらの方法のほうがメモリ使用量が少なくなるため、良いと思います。
There was a problem hiding this comment.
私も同意です。無意識のうちに頭の中に右側が大きくなる数直線を連想することが多いので、right, leftは小さい値からスタートするこちらの方が直感的だなと感じました。
There was a problem hiding this comment.
ありがとうございます、どちらでも良い場合は順方向がやはりイメージしやすいですね。
There was a problem hiding this comment.
bisect_leftの実装は良いと思いました。以前整理したことがあるので、こちら参考になるかもしれません。
https://github.com/olsen-blue/Arai60/blob/41171886bb6299943cdcdf8e92e08bdc2833580f/349.%20Intersection%20of%20Two%20Arrays.md#bisect_left
increasing_subsequenceは、[]で初期値にしておいて、appendしながら構築すると、最後の答えの値を len(increasing_subsequence)で取得できるので、こちらの方がシンプルかもしれません。ご検討ください。
(上でnodchipさんも同じこと言ってましたね...すみません。ご放念ください。)
There was a problem hiding this comment.
ありがとうございます〜。全然、同じことでもその分皆さんが気になる点かと思うので、参考になります。復習時にこちらの方法で書いてみます。
|
拝見しました。 |
There was a problem hiding this comment.
MAX_INT は、普通は int の最大値、Python2 では sys.maxint 3 では sys.maxsize C では INT_MAX のことだと考えるでしょう。違うものが入っているのは好ましくないです。
入力の制約を満たさない入力、異常な入力への対処
現実には、おそらく、このコードがプロダクションで使われていたところ、ある日、まったく違う事情でここにアルファベットでない文字が流れるようになって、予期せぬ動作をして、原因探しの旅に出てここに行き着くことになります。そのときにどのような動作をこのコードはしていますか。みたいな想像をしています。
There was a problem hiding this comment.
数字の場合は、だんだんいろいろな事情で大きな数字が入るようになってきて、気がついたら、ここにその数が流れてきて、10001 を超えていたという事が起きるでしょう。で、事故を起こして、顧客に代表が謝罪をしているときに、2年前にこのコードを書いたときには、10000までしか来ないって言われていたので、このコードは悪くありません、となるかということですね。
つまり、そういう可能性を見ながらコードを書けるかなのです。そういう風に話が変わったときにどれくらい柔軟であるべきかなども俎上に載せて計算して書いています。
もちろん、この入力が「年齢」ならば大きな問題はないでしょう。そこらへんは状況次第です。
ただ、たとえば、64ビット符号付き整数の最大値を限界にしておいたら、事故を起こしたときに、他のところも事故を起こしている可能性が高いので、テストなどに引っかかってここが原因になりにくいですね。
There was a problem hiding this comment.
@oda さん
コメントありがとうございます。なるほどです、Leetcodeの入力制約で言っているから or とりあえず64ビット符号付き整数の最大値にしておく、ではなく考え方そのものがそこにあることが大事かなと感じました。頭に入れておいて、意識します。
There was a problem hiding this comment.
このエラー処理を入れた理由が気になりました。自分は不要ではないかと思いました。また、入れるとするなら index < 0 の場合はなぜ処理しないのかというツッコミどころもあると思いました。
https://leetcode.com/problems/longest-increasing-subsequence/description/