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
38 changes: 38 additions & 0 deletions arai60/intersection-of-two-arrays/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## 考察
- 過去に解いたことあり
- 方針
- 積集合をとる(Pythonだと、setに変換して集合演算)
- time: O(n + m), space: O(n + m)
- n: len(nums1), m: len(nums2)
- 片方をHashSetにしてループ処理
- 結果をユニークにして返す
- time: O(n + m), space: O(n + m)
- 直感的な積集合をとる方針でやる
- あとは実装

## Step1
- 集合演算で実装
- time: O(n + m), space: O(n + m)

## Step2
- ほかの人のPRを検索してみた
- sortしてtwo pointersを使う方法もあるみたい
- Ref. https://github.com/Mike0121/LeetCode/pull/30#discussion_r1641596790
- そういえば昨日ちょうどソート済みの2つの配列のintersectionを活用する問題をやった
- https://leetcode.com/problems/get-the-maximum-score/description/
- もともとソート済みならO(min(n, m))なので速い
- この手法でもやってみる
- この問題の場合は、ソートがボトルネックになる

Choose a reason for hiding this comment

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

確認されてるかもですが、関連ドキュメント貼っておきます。
https://docs.python.org/ja/3/howto/sorting.html#sorting-techniques

Timsort
https://en.wikipedia.org/wiki/Timsort

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます、一通り読みました。
Pythonのソートは3.10まではTimsortで3.11からはPowersortというアルゴリズムが使われていてどちらもmerge sortベースなんですね。
list.sort() を使っても sorted() を使っても、最悪メモリ使用量がO(n)になるというところを見落としていました(list.sort() は何かしら最適化されていてメモリ使用量O(1)でできるのかと思ってました...)

Copy link

Choose a reason for hiding this comment

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

in place な merge sort 存在するんですが、知らなくてもいいでしょう。

Knuth の本でも練習問題だそうです。
https://stackoverflow.com/questions/2571049/how-to-sort-in-place-using-the-merge-sort-algorithm

Copy link
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 log n + m log m), space: O(min(n, m))

## Step3
- 1回目: 22s
- 2回目: 21s
- 3回目: 22s

## Step4
- レビューを元に修正
- ワンライナーでも良さそうなので、一行で記述した
- two pointersの方も修正
- `answer` -> `intersection`
- `list.sort()` を使ってもメモリO(n)のため、引数に破壊的変更を加えない形に修正
5 changes: 5 additions & 0 deletions arai60/intersection-of-two-arrays/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
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)
Comment on lines +3 to +5

Choose a reason for hiding this comment

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

好みですが、

return list(set(nums1) & set(nums2))

こうしちゃってもいいかもですね。

24 changes: 24 additions & 0 deletions arai60/intersection-of-two-arrays/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1.sort()
nums2.sort()

index_nums1 = 0
index_nums2 = 0
answer = []

Choose a reason for hiding this comment

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

具体的に何が入っているか分かる変数名にするのも一考かと。
問題名になっちゃいますが、intersection_of_two_arraysとか如何でしょう。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。
answer -> intersection とすると良さそうです。

while index_nums1 < len(nums1) and index_nums2 < len(nums2):
if nums1[index_nums1] < nums2[index_nums2]:
index_nums1 += 1
continue
if nums1[index_nums1] > nums2[index_nums2]:
index_nums2 += 1
continue

common = nums1[index_nums1]
answer.append(common)
while index_nums1 < len(nums1) and nums1[index_nums1] == common:
index_nums1 += 1
while index_nums2 < len(nums2) and nums2[index_nums2] == common:
index_nums2 += 1

return answer
5 changes: 5 additions & 0 deletions arai60/intersection-of-two-arrays/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
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)
3 changes: 3 additions & 0 deletions arai60/intersection-of-two-arrays/step4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))
24 changes: 24 additions & 0 deletions arai60/intersection-of-two-arrays/step4_two_pointers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1_sorted = sorted(nums1)
nums2_sorted = sorted(nums2)

index_nums1 = 0
index_nums2 = 0
intersection = []
while index_nums1 < len(nums1_sorted) and index_nums2 < len(nums2_sorted):
if nums1_sorted[index_nums1] < nums2_sorted[index_nums2]:
index_nums1 += 1
continue
if nums1_sorted[index_nums1] > nums2_sorted[index_nums2]:
index_nums2 += 1
continue

common = nums1_sorted[index_nums1]
intersection.append(common)
while index_nums1 < len(nums1_sorted) and nums1_sorted[index_nums1] == common:
index_nums1 += 1
while index_nums2 < len(nums2_sorted) and nums2_sorted[index_nums2] == common:
index_nums2 += 1

return intersection