diff --git a/1-Two-Sum/note.md b/1-Two-Sum/note.md new file mode 100644 index 0000000..0c69aad --- /dev/null +++ b/1-Two-Sum/note.md @@ -0,0 +1,55 @@ +# 1. 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つだけ持った方がコード自体がとてもシンプルになるという利点があるのでそっちで書いてみる + +- + - nums を1回だけなめて辞書に詰める or ペアを見つける の2者択一をやると速いし、自分自身とのペアになっていないかをチェックしなくて良い + - 型は 3.9 からビルトインの小文字の方を使うのが推奨になっているようだ + - + - ループの最初で `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 に到達した時点であとはもう片方が答えに近づくだけであり行きすぎることはない。 + - 指滑らせて棒の重心探すやつみたい +- 他にも読んだコード + - + - + +## step3(10分以内にさっとかける * 3回) + +step2で書いたソート版は、front < rear を確かめてないと答えが存在しなかった時にすれ違ってエラーで落ちる diff --git a/1-Two-Sum/step1.py b/1-Two-Sum/step1.py new file mode 100644 index 0000000..8442ac4 --- /dev/null +++ b/1-Two-Sum/step1.py @@ -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]] = {} + 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]] diff --git a/1-Two-Sum/step2.py b/1-Two-Sum/step2.py new file mode 100644 index 0000000..ce9f2a8 --- /dev/null +++ b/1-Two-Sum/step2.py @@ -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] diff --git a/1-Two-Sum/step2_sort.py b/1-Two-Sum/step2_sort.py new file mode 100644 index 0000000..3b0a48f --- /dev/null +++ b/1-Two-Sum/step2_sort.py @@ -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]] diff --git a/1-Two-Sum/step3.py b/1-Two-Sum/step3.py new file mode 100644 index 0000000..ce9f2a8 --- /dev/null +++ b/1-Two-Sum/step3.py @@ -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]