-
Notifications
You must be signed in to change notification settings - Fork 0
Add 349. Intersection of Two Arrays.md #13
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
Open
t0hsumi
wants to merge
2
commits into
main
Choose a base branch
from
349
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
# step 1 | ||
考えたこと | ||
- nums1, num2で二重ループ作って、値比較すれば解ける | ||
- num1, num2のどちらかをhashtableに入れればループが一つ減る | ||
- 値->存在するか否かのboolがほしい | ||
- ならsetでいいか | ||
- unique elementだけのリストを返さないといけない | ||
- 一つだけsetを取ると、返り値を保存しているlistのuniqueチェックをどこかでしないといけない | ||
- 両方setをとってintersectionするのが穏当そう | ||
|
||
```python | ||
class Solution: | ||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: | ||
set1 = set(nums1) | ||
set2 = set(nums2) | ||
return list(set1 & set2) | ||
``` | ||
|
||
n, mをnums1.length, num2.lengthとして | ||
- time complexity: O(m + n) | ||
- space complexity: O(m + n) | ||
|
||
# step 2 | ||
- 一応,`element in list`の挙動を確認した | ||
- https://github.com/python/cpython/blob/30efede33ca1fe32debbae93cc40b0e7e0b133b3/Objects/listobject.c#L619-L636 | ||
- 特別なことはなく、端から端まで調べているで良さそう | ||
- set intersectionの挙動 | ||
- https://github.com/python/cpython/blob/39e69a7cd54d44c9061db89bb15c460d30fba7a6/Objects/setobject.c#L1354 | ||
- [要素数の小さいsetをiterateする様にしていた](https://github.com/python/cpython/blob/39e69a7cd54d44c9061db89bb15c460d30fba7a6/Objects/setobject.c#L1372-L1376)ので、両方setでintersectionを取るときはこの操作自体はO(min(m, n)) | ||
- https://github.com/katataku/leetcode/pull/12/files | ||
- 「setに変換したりlistに変換したりするのって意外と抵抗がある」 | ||
- 変換にはすべての要素を走査するコストがあるので、その点を理解する必要がある。 | ||
- https://github.com/nittoco/leetcode/pull/15#discussion_r1632066961 | ||
- 追加の問題として、片方が非常に大きくてもう片方が非常に小さい場合、特に大きいほうがsortされている場合 | ||
- 両方sortされている場合 | ||
- https://github.com/tarinaihitori/leetcode/pull/13 | ||
- step1の様な書き方をして、わざわざsetしたものを変数でおく必要はない。 | ||
- setを一つだけ使う(というより、space complexityをO(min(m, n))としたい場合の)解法 | ||
- これも片方がものすごく大きい場合どうするかに相当するとおもった。 | ||
- https://github.com/hroc135/leetcode/pull/13/files | ||
- pythonでも同様だが、[変数名に型の情報を不必要に入れるべきでない](https://google.github.io/styleguide/pyguide.html#2144-decision:~:text=names%20that%20needlessly%20include%20the%20type%20of%20the%20variable%20(for%20example%3A%20id_to_name_dict))というスタイルがある | ||
- 今回はintersectionだけだと関数名と同じになるし、intersectionで想定するのが集合な気がするが、返り値はintersectionを保持するリストであるので、型名を入れることは許容範囲に感じた | ||
- こういう簡単な問題だと特に、問題を見たときに想定する範囲や取り出す知識の幅がまだまだ小さい様に感じた。 | ||
|
||
片方が非常に大きくてもう片方が非常に小さい場合 | ||
m = large_nums.length, n = small_nums.lengthとして、 | ||
- time complexity: O(m + n) | ||
- space complexity: O(n) | ||
`small_nums_set.remove(num)`をなくして、ループないで`if num in intersection_list`とすることもできる。が、この場合、intesection_listを全て調べることになる。 | ||
```python | ||
class Solution: | ||
def intersection(self, large_nums: List[int], small_nums: List[int]) -> List[int]: | ||
small_nums_set = set(small_nums) | ||
intersection_list = [] | ||
for num in large_nums: | ||
if num in small_nums_set: | ||
small_nums_set.remove(num) | ||
intersection_list.append(num) | ||
return intersection_list | ||
``` | ||
|
||
片方が非常に大きくてもう片方が非常に小さい場合、特に大きいほうがsortされている想定 | ||
m = large_nums.length, n = small_nums.length、sort処理を無視するとして、 | ||
- time complexity: O(n log m) | ||
- space complexity: O(min(m, n)) = O(n) | ||
```python | ||
class Solution: | ||
def intersection(self, large_nums: List[int], small_nums: List[int]) -> List[int]: | ||
def is_member(sorted_nums: List[int], element: int) -> bool: | ||
left = 0 | ||
right = len(sorted_nums) | ||
while left < right: | ||
mid = (left + right) // 2 | ||
if sorted_nums[mid] == element: | ||
return True | ||
elif sorted_nums[mid] < element: | ||
left = mid + 1 | ||
else: | ||
right = mid | ||
return False | ||
sorted_large_nums = sorted(large_nums) | ||
intersection_list = [] | ||
for num in small_nums: | ||
if num in intersection_list: | ||
continue | ||
if is_member(sorted_large_nums, num): | ||
intersection_list.append(num) | ||
return intersection_list | ||
``` | ||
|
||
両方sortされている想定 | ||
|
||
sort処理を無視すれば、 | ||
- time complexity: O(m + n) | ||
- space complexity: O(min(m, n)) | ||
```python | ||
class Solution: | ||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: | ||
sorted_nums1 = sorted(nums1) | ||
sorted_nums2 = sorted(nums2) | ||
index1 = 0 | ||
index2 = 0 | ||
intersection_set = set() | ||
while index1 < len(sorted_nums1) and index2 < len(sorted_nums2): | ||
if sorted_nums1[index1] == sorted_nums2[index2]: | ||
intersection_set.add(sorted_nums1[index1]) | ||
index1 += 1 | ||
index2 += 1 | ||
Comment on lines
+105
to
+108
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. ここのところ、同じものが見つかったら、同じ間ポインターを進めるようにすると、 |
||
elif sorted_nums1[index1] < sorted_nums2[index2]: | ||
index1 += 1 | ||
else: | ||
index2 += 1 | ||
return list(intersection_set) | ||
``` | ||
|
||
# step 3 | ||
|
||
```python | ||
class Solution: | ||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: | ||
return list(set(nums1) & set(nums2)) | ||
``` | ||
|
||
# step 4 | ||
コメントまとめ | ||
- 略語は避けるが慣習として明らかならよい | ||
- 同じ値がきたら、違う値になるまでindexを進める方法もある | ||
- 人に説明する時にこっちの方が自然な形のように感じた。 | ||
|
||
- time complexity: O(m + n) | ||
- space complexity: O(m + n) | ||
```python | ||
class Solution: | ||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: | ||
return list(set(nums1) & set(nums2)) | ||
``` | ||
|
||
|
||
想定 | ||
- どちらも昇順にsortされている | ||
- indexを用意して動かす | ||
- time complexity: O(max(m, n)) | ||
- 片方が大きく、片方が小さい(mを大きい方の要素数、nを小さい方とする) | ||
- sortとかはされてない | ||
- 片方をsetに変換する。もう片方をiterate | ||
- time complexity: O(m + n) = O(n) | ||
- space complexity: O(n) | ||
- 大きい方がsortされている | ||
- quick select: | ||
- time complexity: O(n log m) | ||
- space complexity: O(n) | ||
- 小さい方がsortされている | ||
- sortされてない場合と同じように解くとtime complexityは小さくなる | ||
|
||
昇順sort済み | ||
```python | ||
class Solution: | ||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: | ||
sorted_nums1 = sorted(nums1) | ||
sorted_nums2 = sorted(nums2) | ||
result = [] | ||
index1 = 0 | ||
index2 = 0 | ||
while index1 < len(sorted_nums1) and index2 < len(sorted_nums2): | ||
if sorted_nums1[index1] < sorted_nums2[index2]: | ||
index1 += 1 | ||
continue | ||
if sorted_nums1[index1] > sorted_nums2[index2]: | ||
index2 += 1 | ||
continue | ||
|
||
duplicated_value = sorted_nums1[index1] | ||
result.append(duplicated_value) | ||
while ( | ||
index1 < len(sorted_nums1) | ||
and sorted_nums1[index1] == duplicated_value | ||
): | ||
index1 += 1 | ||
while ( | ||
index2 < len(sorted_nums2) | ||
and sorted_nums2[index2] == duplicated_value | ||
): | ||
index2 += 1 | ||
return result | ||
``` | ||
|
||
```python | ||
class Solution: | ||
def intersection(self, small_nums: List[int], large_nums: List[int]) -> List[int]: | ||
small_nums_set = set(small_nums) | ||
result = [] | ||
for number in large_nums: | ||
if number in small_nums_set: | ||
result.append(number) | ||
small_nums_set.remove(number) | ||
return result | ||
``` | ||
|
||
```python | ||
class Solution: | ||
def intersection(self, small_nums: List[int], large_nums: List[int]) -> List[int]: | ||
def is_member(number: int, sorted_nums: List[int]) -> bool: | ||
left = 0 | ||
right = len(sorted_nums) | ||
while left < right: | ||
mid = (left + right) // 2 | ||
if sorted_nums[mid] == number: | ||
return True | ||
if sorted_nums[mid] < number: | ||
left = mid + 1 | ||
else: | ||
right = mid | ||
return False | ||
|
||
sorted_large_nums = sorted(large_nums) | ||
result = [] | ||
for number in small_nums: | ||
if number in result: | ||
continue | ||
if is_member(number, sorted_large_nums): | ||
result.append(number) | ||
return result | ||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
関数名がintersectionであることから積集合を返すことが容易に想像できるので、ローカル変数名はresでもいいかもしれませんね
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.
res は略語ですが1000件ちょっと使われていますね。result のほうが5000件強で多いは多いです。
https://source.chromium.org/search?q=%22return%20res;%22%20filepath:.*%5C.cc$&sq=
https://source.chromium.org/search?q=%22return%20result;%22%20filepath:.*%5C.cc$&sq=
略語は避けるが慣習として明らかならよい、という話でしょう。
略語は略し方の不一致から、たまに気が付きにくい事故を起こします。たとえば、C++ で継承をしようとして Id と ID を間違えると、意図せずに新たに関数を定義してしまうことになります。
これ自体は C++11 からの override つけておきましょう、ですが、英単語を使うことで綴りが違うことへの違和感をより使おうという話です。