|
| 1 | +# [Problem 350: Intersection of Two Arrays II](https://leetcode.com/problems/intersection-of-two-arrays-ii/description/?envType=daily-question&envId=2024-07-02) |
| 2 | + |
| 3 | +## Initial thoughts (stream-of-consciousness) |
| 4 | +- easiest way would probably be to sort both arrays and then iterate through them in the same loop, check the current value in one against the current value in the other, etc... |
| 5 | +- but the sorting upfront is going to take $O(n \log n)$ (Timsort)... I think there's a way to do it in $O(n)$, where we just run through each list one time. Roughly: |
| 6 | + - loop through one list, get counts of each unique value, store counts in a dict (keys=unique values, values=counts) |
| 7 | + - does it matter which one? Don't think so?... |
| 8 | + - does leetcode let you import standard library modules? If so, could use `collections.Counter` instead, or `collections.defaultdict(int)` + loop (former would be faster, I think?) |
| 9 | + - actually... if we can use standard library modules `collections.Counter` would make this problem trivial since it supports multiset operations. *Probably* would be faster than implementing manually? But let's compare to see... |
| 10 | + - create 2nd dict of counts for 2nd list, loop through 2nd list |
| 11 | + - For each item in 2nd list, if the item is a key in the first dict and its count in the 1st dict is > its current count in the 2nd dict, then: |
| 12 | + - append the item to the output list |
| 13 | + - increment the item's count in the 2nd dict by 1 |
| 14 | + - return the output list |
| 15 | + |
| 16 | +## Refining the problem |
| 17 | + |
| 18 | +## Attempted solution(s) |
| 19 | +If we can use standard library modules, the simplest solution is: |
| 20 | + |
| 21 | +**Solution 1:** |
| 22 | +```python |
| 23 | +from collections import Counter |
| 24 | + |
| 25 | +class Solution: |
| 26 | + def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: |
| 27 | + nums1_counts = Counter(nums1) |
| 28 | + nums2_counts = Counter(nums2) |
| 29 | + nums_intersection = nums1_counts & nums2_counts |
| 30 | + return list(nums_intersection.elements()) |
| 31 | +``` |
| 32 | + |
| 33 | +If not, then we can do: |
| 34 | + |
| 35 | +**Solution 2:** |
| 36 | +```python |
| 37 | +class Solution: |
| 38 | + def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: |
| 39 | + nums1_counts = {} |
| 40 | + for num in nums1: |
| 41 | + nums1_counts[num] = nums1_counts.get(num, 0) + 1 |
| 42 | + |
| 43 | + nums2_counts = {} |
| 44 | + nums_intersection = [] |
| 45 | + for num in nums2: |
| 46 | + try: |
| 47 | + count_in_nums1 = nums1_counts[num] |
| 48 | + except KeyError: |
| 49 | + continue |
| 50 | + if count_in_nums1 > nums2_counts.setdefault(num, 0): |
| 51 | + nums_intersection.append(num) |
| 52 | + nums2_counts[num] += 1 |
| 53 | + |
| 54 | + return nums_intersection |
| 55 | +``` |
| 56 | + |
| 57 | +Comparing the two solutions: |
| 58 | + |
| 59 | +**Solution 1:** |
| 60 | + |
| 61 | + |
| 62 | +**Solution 2:** |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +Looks like Solution 1 is *slightly* faster... |
| 67 | + |
| 68 | +...though I clicked submit for each of these multiple times and the variability in the runtime was surprisingly high relative to the total runtime -- one of the times I submitted Solution 1, it took 59ms and beat only 12.30% of other submissions. I assume each submission runs against the same test cases, so the difference is probably just inherent variability in code execution and/or whatever overhead is added by the leetcode runner. Given that, any "real" difference between these two solutions is probably negligible. And in fact, the runtime savings of these two solutions versus the $O(n \log n)$ solution might not even be worth it, since both of these two solutions need to allocate additional memory to store the counts dicts. |
0 commit comments