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
53 changes: 53 additions & 0 deletions problems/1.two-sum/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## step1
- (step1)二重ループにするとO(n2)で解けそう
- 全部回すと10^8/2くらいでpythonでもギリギリいけそう
- (step1-2)sortしてあったら二分探索で片方を見つけた時に二分探索で答えを探せそう
- ソートでO(NlogN)、N回二分探索でO(NlogN)
- indexをつけて、sortするには下記のようにするみたい
- 実装したが、indexずらすのとかで結構ごちゃごちゃしたコードになった
```py
indexed_data = list(enumerate(data))

# 値(タプルの2番目の要素)でソート
# 値が同じ場合は元のインデックス(タプルの1番目の要素)で安定ソートされる
sorted_indexed_data = sorted(indexed_data, key=lambda item: item[1])
```


- (step1-3)いやそもそも1回のfor文でこれまで辿ってきた履歴に求める数があるかどうかで答えが出せるはず
- 出てきた数をkey,indexをvalueにしておく、答えは1つに求まるのでindexの上書きは気にしなくていい

leetcode上での数値は下記
O(n2)の解法:1716ms
O(nlogn)の解法:111ms
O(n)の解法:0ms
## step2
- 問題としては答えがあることを保証しているが、答えがない場合はNoneを返すのがいいと思う
- また答えが複数あるケースでバグるようなことがないかは気にしておきたい
- 今回は大丈夫
- 他の人のコードをみる
- https://github.com/mamo3gr/arai60/pull/11/files
- 配列の長さが0,1の時エラーを投げてるのはいいと思う
- エラーを返すかNoneを返すか毎回悩む
- `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.

単語を知らないのは仕方がないし、実際の仕事の場面では調べるなどできると思います。
どう考えるか、どういう価値観を持つかを気にしましょう。


```
数学・アルゴリズムの世界では昔から:
a + b = target
b は a の complement
という言い方をします。
```

- https://github.com/MasukagamiHinata/Arai60/pull/9/files
- `メソッドの出力のtype hintがList[int]となっているので、ここをOptional[List[int]]]としてNoneも返りうることを明示しておくか、return [-1, -1]など型のあった返り値にすると良い気がします。`
- 答えがない時に、[-1,-1]も考えたが-1だと後続の処理で配列の末尾を指して処理が進み、意図しないところでバグが健在化する可能性があるので、Noneかエラーにした方が親切だと自分は判断した
- `あとは設計思想の問題ですが、複数解に対応するということは利用者は解が何個あるか知らないことが想定され、その中には解が含まれないケースも含まれると思います。解が何個あるか知るために使ったところ0個で、エラーが出ると利用者としては少々仰々しくて使いにくいという気持ちになりそうだと思いました。(解が最低1個あることを先に調べないとエラーが出てしまうため。)自分なら、解が0個のとき、つまりresults = []のときでもそのままreturnするように書くと思います。`
- 確かに、複数の解を想定している場合は解がない場合にエラーはやめてほしいと思った。このような想定されるケースへの拡張性を考慮に入れて、エラーを投げるかNoneを返すか迷った際にNoneを選択できるといいと思った。
- dictの命名でkey_to_valueはとても良いので毎回候補の中に入れるようにしたい
- checked_は今回のような短いコードの場合はすぐわかるので書かなくて良さそう
- step1-2でミスでtupleで返してもLeetCode的にOKになっていた
- 内部的にどういう感じでOK/NGの判定をしているのかイメージしたところfor文で判定してたりするとこのような現象が起こりそうだと思った
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

予想として、順序が違っても正解にしたいので
expected == sorted(actual) とかにしているのではないですかね。


## step3
- 短かったのと頭の中で整理ができていたのとで難なく書けた

33 changes: 33 additions & 0 deletions problems/1.two-sum/step1-2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#
# @lc app=leetcode id=1 lang=python3
#
# [1] Two Sum
#
import bisect


# @lc code=start
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
index_nums = list(enumerate(nums))
sorted_index_nums = sorted(index_nums, key=lambda item: item[1])

for index, (root_index, num) in enumerate(sorted_index_nums):
search_num = target - num
candidate_index = (
bisect.bisect_left(
sorted_index_nums[index + 1 :], search_num, key=lambda x: x[1]
)
+ index
+ 1
)
if candidate_index >= len(sorted_index_nums):
continue
if sorted_index_nums[candidate_index][1] == search_num:
return (
min([root_index, sorted_index_nums[candidate_index][0]]),
max([root_index, sorted_index_nums[candidate_index][0]]),
)


# @lc code=end
18 changes: 18 additions & 0 deletions problems/1.two-sum/step1-3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#
# @lc app=leetcode id=1 lang=python3
#
# [1] Two Sum
#
# @lc code=start
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
checked_num_index = {}

for index, num in enumerate(nums):
seached_num = target - num
if seached_num in checked_num_index:
return [checked_num_index[seached_num], index]
checked_num_index[num] = index


# @lc code=end
16 changes: 16 additions & 0 deletions problems/1.two-sum/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#
# @lc app=leetcode id=1 lang=python3
#
# [1] Two Sum
#

# @lc code=start
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]


# @lc code=end
21 changes: 21 additions & 0 deletions problems/1.two-sum/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# @lc app=leetcode id=1 lang=python3
#
# [1] Two Sum
#

# @lc code=start
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
num_to_index = {}

for index, num in enumerate(nums):
complement = target - num
if complement in num_to_index:
return [num_to_index[complement], index]
num_to_index[num] = index

return


# @lc code=end
21 changes: 21 additions & 0 deletions problems/1.two-sum/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# @lc app=leetcode id=1 lang=python3
#
# [1] Two Sum
#

# @lc code=start
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
num_to_index = {}

for index, num in enumerate(nums):
complemnt = target - num
if complemnt in num_to_index:
return [num_to_index[complemnt], index]
num_to_index[num] = index

return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

実際はここに来たら、想定と違う入力だということですよね。実務上どうするかを考えてみると、よりこの問題を味わえると思います。



# @lc code=end