-
Notifications
You must be signed in to change notification settings - Fork 0
1 two sum #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
1 two sum #12
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # 1. Two Sum | ||
|
|
||
| <https://leetcode.com/problems/two-sum/> | ||
|
|
||
| ## step1(まず通す) | ||
|
|
||
| 配列長さ n に対して、任意の2要素の和を計算しようとすると n(n+1)/2 回の足し算~~とそれを保存するスペース~~が必要だが、以下のやり方で時間計算量、空間計算量ともに O(n) でできる | ||
|
|
||
| 1. `{num:list of indices}` の辞書を作る | ||
| 2. nums の先頭から順に、 キーが `target - num` であるような辞書の要素(num と足して target になってくれるような他の `nums` の要素)が存在するかを見ていく | ||
|
|
||
| 気をつけるポイント | ||
|
|
||
| 1. 同じ値が複数ある時は index はリストになる | ||
| 2. その際、 3+3=6 みたいな時はリストの中からインデックスを選ぶ方法に注意する(同じインデックスのペアは禁止) | ||
| 1. 結局書いたコードは、答えが一意じゃなくても最初に見つかったやつを返してくれるコードになった | ||
| 2. 答えが一意を鵜呑みにするなら、ペアが見つかった時に以下のように判定できるが汎用性が低そう | ||
| 1. pair_indices が長さ 1 なら [index, pair_indices[0]] が答え | ||
| 2. pair_indices の長さが 2 なら pair_indices が答え | ||
| 3. 実は、num_to_indices は index のリストじゃなくて同じ値のうち最後に見つかったやつのインデックスだけを持ってもいい | ||
| 1. 答えを一つだけ返すという前提なら答えが一意じゃなくてもこれでいい | ||
| 2. しかし、「あれ、これでいいんだっけ?」とはなりやすそうだし target になる全部のペア返して、となった時に変更が大きくなりそう | ||
|
|
||
| ## step2(整形&他の人のコードを読む) | ||
|
|
||
| 先ほどは | ||
| > 実は、num_to_indices は index のリストじゃなくて同じ値のうち最後に見つかったやつのインデックスだけを持ってもいい | ||
| > | ||
| > 答えを一つだけ返すという前提なら答えが一意じゃなくてもこれでいい | ||
| > | ||
| > しかし、「あれ、これでいいんだっけ?」とはなりやすそうだし target になる全部のペア返して、となった時に変更が大きくなりそう | ||
|
|
||
| と思っていたが、今回のコードだと1つだけ持った方がコード自体がとてもシンプルになるという利点があるのでそっちで書いてみる | ||
|
|
||
| - <https://github.com/huyfififi/coding-challenges/pull/1> | ||
| - nums を1回だけなめて辞書に詰める or ペアを見つける の2者択一をやると速いし、自分自身とのペアになっていないかをチェックしなくて良い | ||
| - 型は 3.9 からビルトインの小文字の方を使うのが推奨になっているようだ | ||
| - <https://github.com/huyfififi/coding-challenges/pull/1#discussion_r2002951658> | ||
| - ループの最初で `num = nums[index]` しなくて `enumerate` でいい | ||
| - ソートする方とはなんだろう? | ||
| - ソートして、先頭と末尾の和から見ていって↓を繰り返すとか? | ||
| - 和が target より大きいなら、後ろのポインタを一つ前に | ||
| - 〃小さいなら、前のポインタを一つ後ろに | ||
| - これでうまくいくの? | ||
| - うまく例が作れないがポインタが行きすぎてしまったりしないのか? | ||
| - いろんな例を考えてるがならなそう | ||
| - 証明: `num[answer1] + num[answer2] (answer1 < answer2) = target` になるとき、`i < answer1 < answer2 < j` に対しての `num[i] + num[j]` は target より大きいか小さいかわからないけど、`num[i] + num[answer2] < target < num[answer1] + num[j]` なのでどちらかが answer に到達した時点であとはもう片方が答えに近づくだけであり行きすぎることはない。 | ||
| - 指滑らせて棒の重心探すやつみたい | ||
| - 他にも読んだコード | ||
| - <https://github.com/naoto-iwase/leetcode/pull/11/changes> | ||
| - <https://github.com/shintaro1993/arai60/pull/15/changes> | ||
|
|
||
| ## step3(10分以内にさっとかける * 3回) | ||
|
|
||
| step2で書いたソート版は、front < rear を確かめてないと答えが存在しなかった時にすれ違ってエラーで落ちる | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| from typing import Dict, List | ||
|
|
||
|
|
||
| class Solution: | ||
| def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
| num_to_indices: Dict[int, List[int]] = {} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python 3.9 以降では dict[int, list[int]] と書けるようです。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます。そのようですね。↓のコメントでも言及されていますね。 |
||
| for index in range(len(nums)): | ||
| num = nums[index] | ||
| if num in num_to_indices: | ||
| num_to_indices[num].append(index) | ||
| else: | ||
| num_to_indices[num] = [index] | ||
|
|
||
| for index in range(len(nums)): | ||
| num = nums[index] | ||
| pair_indices = num_to_indices.get(target - num) | ||
| if pair_indices is None: | ||
| continue | ||
| pair_indices = [ | ||
| pair_index for pair_index in pair_indices if pair_index != index | ||
| ] | ||
| if not pair_indices: | ||
| continue | ||
| return [index, pair_indices[0]] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| class Solution: | ||
| def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
| num_to_index = {} | ||
| for index, num in enumerate(nums): | ||
| pair_index = num_to_index.get(target - num) | ||
| if pair_index is None: | ||
| num_to_index[num] = index | ||
| continue | ||
| return [index, pair_index] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| class Solution: | ||
| def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
| num_and_index = sorted([(num, index) for index, num in enumerate(nums)]) | ||
| front = 0 | ||
| rear = len(nums) - 1 | ||
| while front < rear: | ||
| sum_ = num_and_index[front][0] + num_and_index[rear][0] | ||
| if sum_ < target: | ||
| front += 1 | ||
| continue | ||
| if target < sum_: | ||
| rear -= 1 | ||
| continue | ||
| return [num_and_index[front][1], num_and_index[rear][1]] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| class Solution: | ||
| def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
| num_to_index = {} | ||
| for index, num in enumerate(nums): | ||
| pair_index = num_to_index.get(target - num) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. complementという書き方をされている方も見かけました。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます。補数ということですね。より実態を表した名前だと思います。 |
||
| if pair_index is None: | ||
| num_to_index[num] = index | ||
| continue | ||
| return [index, pair_index] | ||
|
Comment on lines
+1
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 自分のコードは2回ループしてたので,違う書き方で参考になりました. 同一indexでないというチェックがないのはなぜだろう,というようなことを考えてたりしましたが,1回ループverだと不要になるんですね.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 私も最初はそうしてたのですが、 huyfififi/coding-challenges#1 を見てなるほどと思い、真似してみました |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
他の人のコードも見つけてきましたが,言及されている通りのようですね
https://github.com/fuga-98/arai60/pull/12/changes#diff-e05ee5891f6b31ddafd0fa4d5497330fedc2954d82a170f4b6fc95f8f48d4d2cR41-R64
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます、そのようですね。
この方のコードで、辞書に詰めなくて「set で存在確認→ list.index() で index を取得」というのもなるほどと思いました。