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
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import time
import tracemalloc


def measure(nums1, nums2, label):
print(f"[{label}]")

# ----------------------
# 1. set への移行時間
# ----------------------
tracemalloc.start()
t0 = time.perf_counter()

nums1_set = set(nums1)

t1 = time.perf_counter()
_, peak_set = tracemalloc.get_traced_memory()
tracemalloc.stop()

print(f" set build time: {t1 - t0:.6f} sec")
print(f" set build peak memory: {peak_set / 1024 / 1024:.2f} MB")

# ----------------------
# 2. intersection 時間
# ----------------------
tracemalloc.start()
t2 = time.perf_counter()

result = nums1_set.intersection(nums2)

t3 = time.perf_counter()
_, peak_inter = tracemalloc.get_traced_memory()
tracemalloc.stop()

print(f" intersection time: {t3 - t2:.6f} sec")
print(f" intersection peak memory: {peak_inter / 1024 / 1024:.2f} MB")
print(f" result size: {len(result)}\n")


if __name__ == "__main__":
nums_big = range(10**7) # 安全なサイズ
nums_small = range(10)

measure(nums_big, nums_small, "big set ∩ small")
measure(nums_small, nums_big, "small set ∩ big")
67 changes: 67 additions & 0 deletions problems/349.intersection-of-two-arrays/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## step1
- setの積集合を提出したら良さそうO(min(len(nums1),len(nums2)))なのでO(N)
- s1 & s2 or s1.intersection(s2)で解けそう
- 他の選択肢がないか考える
- 片方をsetにしてforで存在した場合に答えにするパターン
- 片方はsetにしないと1つの要素を調べるのでO(N)使ってしまうので時間がかかりそう

## step2
- 他の人のコードを見てみる
- intersectionを実装する課題と認識する方が良さそう
- https://github.com/Hiroto-Iizuka/coding_practice/pull/13
- set.intersection()の引数はSetだけでなく、 Iterable でOK
- そうすると小さい方をSetにしたくなる感覚はもっておきたい
- list => setに変換するコストとfor文を若干多く回してsetの判定をするコスト感覚を身に付けたい
- 大きい方をSetにする場合と小さい方をSetにする場合で確認する

小さい方を10,大きい方を10**7として比較したところ下記
メモリも実行時間も全く違う
10**7のlist=>setで2.4秒と560MB掛かる
10**7で3秒かかる
```py
[big set ∩ small]
set build time: 2.406463 sec
set build peak memory: 561.17 MB
intersection time: 0.000010 sec
intersection peak memory: 0.00 MB
result size: 10

[small set ∩ big]
set build time: 0.000008 sec
set build peak memory: 0.00 MB
intersection time: 0.000005 sec
intersection peak memory: 0.00 MB
result size: 10
```


- https://github.com/mamo3gr/arai60/pull/13/files
- ソート済みの場合も考えられている
- `assert common == sorted2[j]`の書き方が勉強になった
- ここにくるときは必ずこうなっていますよというコメントのような感じで受け取った
- 最終的には再帰のような感じで要素数を入れ替えている

- https://github.com/Yuto729/LeetCode_arai60/pull/18/files
- `大きいリストの場合それをsetにするのはコストが大きい場合がある. setは内部的にはハッシュテーブルを用いて実装されているので,大きい集合に対してはそれだけハッシュの衝突&リサイズが起きる.`
- c言語のコードはなんとなくしかわからなかったが、上記のコメントはイメージできたので大きいSetを使おうとする場合には上記の操作がされていることを念頭においておきたい

- https://github.com/komdoroid/arai60/pull/3/files
- コメントでのやり取りの中で、取り組んでいるマインドが重要だと再認識した。

- https://github.com/yas-2023/leetcode_arai60/pull/13/files
- `自分が読んだところ、nums1_value, nums2_valueが、深いwhilei < len(nums1) and nums1[i] == nums1_value:を読んでいる辺りぐらいで何の値だったか、頭のキャパから漏れてしまいました。`
- 読んでいる人の感覚を言語化されていてとても良いコメントだと思った。

- https://github.com/naoto-iwase/leetcode/pull/13/files
- intersectionの実装のリンクとPythonでの翻訳が勉強になった。
- 追加質問の例なども勉強になった。


- suggestされて気になって調べたが、`intersection_update`という呼び出しもとのsetを積集合に書き換えるメソッドもあるみたい(`&=`も同じ)
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://docs.python.org/3/library/stdtypes.html#set.intersection_update
こういうリンクを残しておいてもいいと思います。

- 今回は実装上はどちらでも問題なさそうだが、一回上書きしてlistにして返すよりはそのまま積集合をとったままリストで返した方がぱっと見でわかりやすそう


## step3
- コード自体は短いのですんなりかけた
- 今回の問題の設定でnumsの数がさらに大きい場合は、step2で見たsetにしない方法などを検討する必要がありそうだと思った

16 changes: 16 additions & 0 deletions problems/349.intersection-of-two-arrays/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#
# @lc app=leetcode id=349 lang=python3
#
# [349] Intersection of Two Arrays
#

# @lc code=start
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1_set = set(nums1)
nums2_set = set(nums2)

return list(nums1_set & nums2_set)


# @lc code=end
18 changes: 18 additions & 0 deletions problems/349.intersection-of-two-arrays/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#
# @lc app=leetcode id=349 lang=python3
#
# [349] Intersection of Two Arrays
#

# @lc code=start
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
if len(nums1) > len(nums2):
return self.intersection(nums2, nums1)

nums1_set = set(nums1)

return list(nums1_set.intersection(nums2))


# @lc code=end
17 changes: 17 additions & 0 deletions problems/349.intersection-of-two-arrays/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# @lc app=leetcode id=349 lang=python3
#
# [349] Intersection of Two Arrays
#

# @lc code=start
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
if len(nums1) > len(nums2):
return self.intersection(nums2, nums1)
Comment on lines +10 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

小さい方をセットにしたいんだよ、という気持ちは以下のようにも書けそうです。

Suggested change
if len(nums1) > len(nums2):
return self.intersection(nums2, nums1)
smaller = nums1
larger = nums2
if len(smaller) > len(larger):
smaller, larger = larger, smaller

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

再帰を使わないのであれば、個人的には以下のように書きたいです。

Suggested change
if len(nums1) > len(nums2):
return self.intersection(nums2, nums1)
smaller, larger = sorted([nums1, nums2], key=len)

nums1_set = set(nums1)

return list(nums1_set.intersection(nums2))


# @lc code=end