Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions 1-Two-Sum/note.md
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 より大きいなら、後ろのポインタを一つ前に
- 〃小さいなら、前のポインタを一つ後ろに
Comment on lines +40 to +43

Copy link
Copy Markdown

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

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます、そのようですね。
この方のコードで、辞書に詰めなくて「set で存在確認→ list.index() で index を取得」というのもなるほどと思いました。

- これでうまくいくの?
- うまく例が作れないがポインタが行きすぎてしまったりしないのか?
- いろんな例を考えてるがならなそう
- 証明: `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 を確かめてないと答えが存在しなかった時にすれ違ってエラーで落ちる
24 changes: 24 additions & 0 deletions 1-Two-Sum/step1.py
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]] = {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.9 以降では dict[int, list[int]] と書けるようです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。そのようですね。↓のコメントでも言及されていますね。

huyfififi/coding-challenges#1 (comment)

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]]
9 changes: 9 additions & 0 deletions 1-Two-Sum/step2.py
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]
14 changes: 14 additions & 0 deletions 1-Two-Sum/step2_sort.py
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]]
9 changes: 9 additions & 0 deletions 1-Two-Sum/step3.py
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

complementという書き方をされている方も見かけました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分のコードは2回ループしてたので,違う書き方で参考になりました.
miyataka/coding-practice#11

同一indexでないというチェックがないのはなぜだろう,というようなことを考えてたりしましたが,1回ループverだと不要になるんですね.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私も最初はそうしてたのですが、 huyfififi/coding-challenges#1 を見てなるほどと思い、真似してみました