diff --git a/problems/349.intersection-of-two-arrays/measure_big_and_small_size_set.py b/problems/349.intersection-of-two-arrays/measure_big_and_small_size_set.py new file mode 100644 index 0000000..49c0006 --- /dev/null +++ b/problems/349.intersection-of-two-arrays/measure_big_and_small_size_set.py @@ -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") diff --git a/problems/349.intersection-of-two-arrays/memo.md b/problems/349.intersection-of-two-arrays/memo.md new file mode 100644 index 0000000..25795a2 --- /dev/null +++ b/problems/349.intersection-of-two-arrays/memo.md @@ -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を積集合に書き換えるメソッドもあるみたい(`&=`も同じ) + - 今回は実装上はどちらでも問題なさそうだが、一回上書きしてlistにして返すよりはそのまま積集合をとったままリストで返した方がぱっと見でわかりやすそう + + +## step3 +- コード自体は短いのですんなりかけた +- 今回の問題の設定でnumsの数がさらに大きい場合は、step2で見たsetにしない方法などを検討する必要がありそうだと思った + diff --git a/problems/349.intersection-of-two-arrays/step1.py b/problems/349.intersection-of-two-arrays/step1.py new file mode 100644 index 0000000..f0238fa --- /dev/null +++ b/problems/349.intersection-of-two-arrays/step1.py @@ -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 diff --git a/problems/349.intersection-of-two-arrays/step2.py b/problems/349.intersection-of-two-arrays/step2.py new file mode 100644 index 0000000..17bd80b --- /dev/null +++ b/problems/349.intersection-of-two-arrays/step2.py @@ -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 diff --git a/problems/349.intersection-of-two-arrays/step3.py b/problems/349.intersection-of-two-arrays/step3.py new file mode 100644 index 0000000..a347077 --- /dev/null +++ b/problems/349.intersection-of-two-arrays/step3.py @@ -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) + nums1_set = set(nums1) + + return list(nums1_set.intersection(nums2)) + + +# @lc code=end