-
Notifications
You must be signed in to change notification settings - Fork 0
Add 1. Two Sum.md #11
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?
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,130 @@ | ||
# step 1 | ||
解くこと自体は簡単だった。 | ||
|
||
与えられた数値を持つindexを`num_to_index`にいれて記録したが、同じ値があった場合、後からでた | ||
もののindexしか記録しない様になっている。全ての組み合わせを出せとかだとうまくいかない。 | ||
|
||
条件を満たす組がちょうど一つしか存在しないという仮定があったためこの様にした。この仮定のもとで | ||
わざわざ`num_to_indices`とかにするのも不必要に複雑かと判断した。 | ||
|
||
条件を満たす組がない場合、Noneを返すか、例外を発生させるか迷った。 | ||
type annotation的に後者のほうがいいと判断した。 | ||
|
||
```python | ||
class Solution: | ||
def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
num_to_index = dict() | ||
for i in range(len(nums)): | ||
rest = target - nums[i] | ||
if rest in num_to_index: | ||
return [num_to_index[rest], i] | ||
|
||
num_to_index[nums[i]] = i | ||
|
||
raise RuntimeError( | ||
f"No pair found in twoSum(): nums = {nums}, target = {target}" | ||
) | ||
``` | ||
# step 2 | ||
- https://github.com/katataku/leetcode/pull/10/files | ||
- 入力をsortして、両端から調べていく解法もある | ||
- `for i, num in enumerate(nums):`使っていた。`range(len(nums))`よりも簡潔(関数呼び出しの数が少なく)でよさそう | ||
- https://github.com/haniwachann/leetcode/pull/2 | ||
- `for (int i = 0; i < nums.size() - 1; i++)`で-1しない考えもある。空のループが回るだけだから。 | ||
- ボトルネックでないところは、最適化するなを思い出した。 | ||
- https://github.com/philip82148/leetcode-arai60/pull/1 | ||
- 実際にsortしている手法 | ||
|
||
sortして端から抑えていく | ||
|
||
`n = nums.length`として、 | ||
- time complexity: O(n log(n)) | ||
- space complexity: O(n) | ||
```python | ||
class Solution: | ||
def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
num_index_pairs = [] | ||
for i, num in enumerate(nums): | ||
num_index_pairs.append((num, i)) | ||
num_index_pairs.sort() | ||
|
||
left = 0 | ||
right = len(nums) - 1 | ||
while left < right: | ||
two_sum = num_index_pairs[left][0] + num_index_pairs[right][0] | ||
if two_sum == target: | ||
return [num_index_pairs[left][1], num_index_pairs[right][1]] | ||
|
||
if two_sum > target: | ||
right -= 1 | ||
else: | ||
left += 1 | ||
|
||
raise RuntimeError( | ||
f"No pair found in twoSum(): nums = {nums}, target = {target}" | ||
) | ||
``` | ||
|
||
hash tableを使った解法 | ||
`n = nums.length`として、 | ||
- time complexity: O(n) | ||
- space complexity: O(n) | ||
```python | ||
class Solution: | ||
def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
num_to_index = dict() | ||
for i, num in enumerate(nums): | ||
rest = target - num | ||
if rest in num_to_index: | ||
return [num_to_index[rest], i] | ||
|
||
num_to_index[num] = i | ||
|
||
raise RuntimeError( | ||
f"twoSum(): No pair found: nums = {nums}, target = {target}" | ||
) | ||
``` | ||
|
||
# step 3 | ||
|
||
```python | ||
class Solution: | ||
def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
num_to_index = dict() | ||
for i, num in enumerate(nums): | ||
rest_value = target - num | ||
if rest_value in num_to_index: | ||
return [num_to_index[rest_value], i] | ||
|
||
num_to_index[num] = i | ||
raise RuntimeError( | ||
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. RuntimeErrorは適していないような気がします。ドキュメント的には他に当てはまるものがないときの最終手段みたいな感じでしょうか https://docs.python.org/3/library/exceptions.html#RuntimeError
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. builtin errorを使うならValueErrorですかね 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. 私も ValueError のほうかなあと思いました。 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. コメントありがとうございます。 ValueErrorは、関数冒頭で行える様な引数チェックで引っかかる、引数が見るからに適切でない値の時(たとえば今回の問題だと、引数にくるnumsの要素数が1の時)に発生させるイメージでした。 頑張って探した(探せた)けど、求めているものが見つからない場合は、ValueErrorには当たらないのかなぁという判断でした(今回は要素数1もここに入ってしまいますが)。
とあるのでinappropriateの解釈が、ちょっと不適切だったかもしれません。 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. すみません、ちょっと関連して私見を述べたくなったのでコメントさせていただきます こういったもの(エラー以外の例はあんまり思いつきませんが)の方針は、出来るだけより詳細を示せるエラーの型を選ぶとよいと僕は思っています。 ※また、この関数でRuntimeErrorを2か所以上raiseしなければいいというわけでもなく、この関数と一緒に他のRuntimeErrorをraiseする関数と一緒にtry-catchブロックに入れることでも同じ問題が起きます。 究極、(言い過ぎかもしれませんが)型は人間の認識と少しぐらいずれていてもよく、人間にとってはエラー文の方が本命だと思っています。 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. try-catchブロックの中で細かい粒度で例外を捉えられるようにという意識があまりなかったです。勉強になります。 |
||
f"twoSum(): No pair found: nums = {nums}, target = {target}" | ||
) | ||
``` | ||
|
||
# step 4 | ||
コメントまとめ | ||
- このシチュエーションならRuntimeErrorかなとおもったが、odaさん・hayashiさんはValueErrorを挙げていた。自分の感覚が少しずれていそうだった。 | ||
- RuntimeError: Raised when an error is detected that doesn’t fall in any of the other categories. The associated value is a string indicating what precisely went wrong. | ||
- ValueError: Raised when an operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception such as IndexError. | ||
- RuntimeErrorは相当強い条件の中で使うもので、ValueErrorにおける、an inappropriate valueの解釈は自分の想定していたより広くとって良さそう | ||
- dict()と{}が異なる。 | ||
- https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/use-dict-literal.html | ||
- https://madebyme.today/blog/python-dict-vs-curly-brackets/ | ||
- わかりやすくていい記事だった。 | ||
|
||
restからcomplementに変更した。 | ||
```python | ||
class Solution: | ||
def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
num_to_index = {} | ||
for i, num in enumerate(nums): | ||
complement = target - num | ||
if complement in num_to_index: | ||
return [num_to_index[complement], i] | ||
num_to_index[num] = i | ||
raise ValueError( | ||
"twoSum(): No pair found: " | ||
f"nums = {nums}, target = {target}" | ||
) | ||
``` |
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.
{}
でもdictの初期化はできますね。(こちらは構文レベルでサポートされており、dict関数の呼び出しが分、ちょっとパフォーマンス的に良かったりもします。)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.
勝手に
{}
はdict()
のsyntax sugerだと思ってました。パフォーマンスの違い知りませんでした。
ありがとうございます。