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
45 changes: 45 additions & 0 deletions arai60/two-sum/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## 考察
- 過去に何度も解いたことあり
- 方針は4つ思い浮かぶ
- 全探索
- C(n, 2)パターンを全部調べる
- 今回はこの方針はスキップ
- time: O(n^2), space: O(1)
- ハッシュマップ
- 追加のメモリを使用する
- 足し算が可換(答えの順番が関係ない)ので1パスでOK
- 引き算とかだとおそらく1パスではできない
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

a が出てきたときに、x - a = target, a - x = target となるような x があったかを確認すればいいですね。

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.

たしかに両方見れば大丈夫ですね!勉強になりました。

- time: O(n), space: O(n)
- ソートして二分探索
- ソートしたら二分探索可能
- time: O(n log n), space: O(1) -> space: O(1)は勘違いだった。元のインデックスを保持する必要があるので、正しくはO(n)
- ソートして2 pointers
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これ、選択肢になかったです。
参考になりました。

- メモリO(1)の解法では、最速になると思う
- ソートがボトルネックになる
- time: O(n lon n), space: O(1) -> space: O(1)は勘違いだった。元のインデックスを保持する必要があるので、正しくはO(n)

- ハッシュマップを使った手法を選択
- あとは実装

## Step1
- ハッシュマップを使った方法を実装
- time: O(n), space: O(n)

## Step2
- 2 pointersの手法でもやってみる
- ソートするとインデックスが変わるのでそこだけ注意した
- time: O(n log n), space: O(1)

## Step3
- ハッシュマップを使った方法で実装
- 1回目: 1m02s
- 2回目: 55s
- 3回目: 47s

## Step4
- レビューを元に修正
- 変数名を変更
- complement -> complement_value
- Exceptionにメッセージを付与
- 呼び出し元に対して親切に
- enumerateを使ってみた
11 changes: 11 additions & 0 deletions arai60/two-sum/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n = len(nums)
num_to_index = {}
for i in range(n):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

for i, num in enumerate(nums):

という選択肢もありますね。

complement = target - nums[i]
if complement in num_to_index:
return [i, num_to_index[complement]]
num_to_index[nums[i]] = i

raise Exception()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

raise Exception('unreachable')

のようなメッセージを付けると親切かなと思いました。

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.

たしかにこちらの方が親切ですね。見直してみます。

20 changes: 20 additions & 0 deletions arai60/two-sum/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n = len(nums)
nums_with_index = [(nums[i], i) for i in range(n)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

上に、space: O(1)とありますが、この実装だとO(N)になりませんか。

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.

O(1)は勘違いでした。この問題の場合、元のインデックスをどこかで保持する必要があるのでO(n)になりますね。。

nums_with_index.sort()

left = 0
right = n - 1
while left < right:
num_left, index_left = nums_with_index[left]
num_right, index_right = nums_with_index[right]
sum_ = num_left + num_right
if sum_ == target:
return [index_left, index_right]
if sum_ < target:
left += 1
else:
right -= 1

raise Exception()
11 changes: 11 additions & 0 deletions arai60/two-sum/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n = len(nums)
num_to_index = {}
for i in range(n):
complement = target - nums[i]
if complement in num_to_index:
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_valueのように、indexかvalueかをはっきりさせるとより良いかと思いました。remain_valueとかでも良いかもしれません。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私も少し気になりました。

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.

ありがとうございます。変数名見直してみます。

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は十分伝わるかなと思いました。
逆にcomplement_valueだと少し冗長に感じます。(好みの問題ですが...)

complementはこの問題の解答の中で一番わかり易い単語を使われているなと思いました!

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_numでしょうか。
num_to_indexという変数があるので、numかindexかをはっきりさせたいという感覚です。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

erutakoさん
コメントありがとうございます。大きく違うことは言っていないと思っていて、自分も感覚としては、numかindexかをはっきりさせたいができれば良いかな、くらいのニュアンスでした。complement_valueは確かに全体のコード量を鑑みると冗長ですね。

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.

皆様コメントありがとうございます。
一応、自分の感覚もerutakoさんに近いです。最初に、complementと変数名を付けたときは Two's complementを連想していました。
調べてみたところ、この「補数」という単語は「ある数に対してその数を基準として加えることで特定の値(通常は0や2のべき乗)になる数のこと」という意味らしいので、注目している数(nums[i])に対するtargetの補数はvalueであることは比較的明確なのかもと思いました。

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.

と書きましたが、正解はなくどれも選択肢のうちの一つだと思うので考える機会を与えてくださりありがとうございます!

return [i, num_to_index[complement]]
num_to_index[nums[i]] = i

raise Exception()
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://discord.com/channels/1084280443945353267/1235971495696662578/1240719515722190982

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.

ありがとうございます。確認しておきます。

10 changes: 10 additions & 0 deletions arai60/two-sum/step4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
num_to_index = {}
for i, num in enumerate(nums):
complement_value = target - num
if complement_value in num_to_index:
return [i, num_to_index[complement_value]]
num_to_index[num] = i

raise Exception('unreachable')