Number Intersection

def intersects(a, b)
  mem = {}
  a.each { |el| mem[el] ||= true }
  b.filter { |el| mem.delete el }
end

#Challenge

SourceLanguageRuntime
DailyByteruby\(\mathcal{O}(a+b)\)

given two arrays of numbers (not guaranteed unique) return the set (unique) of numbers in both sets.

#Analysis

we build a hashmap storing the characters that occur in a in \(\mathcal{O}(a)\) time and then simply return the characters in b that match a. This has space complexity and time complexity \(\mathcal{O}(n)\) where n is the length of the intersection of a and b.

Note
we've used mem.delete because otherwise if a character in a occurs more than once in b, then we'll end up including it in the return value more than once as well.

#Test Cases

intersects([2, 4, 4, 2], [2, 4]) # [2, 4]
intersects([1, 2, 3, 3], [3, 3]) # [3]
intersects([2, 4, 6, 8], [1, 3, 5, 7]) # return []

#Alternative Implementation

The ruby standard library has its own method to perform this kind of computation.

def intersects(a, b)
  a.intersection b
end

#Another

If we can modify the input arrays in place, we can construct a solution with no space complexity and \(\mathcal{O}(a \; log \; a + b \; log \; b)\) time complexity. This solution has a striking similarity to the jewels and stones solution.

# @return [Integer] the index of the the first element
# in `arr` from `index` which doesn't equal `el`
def non_eq_index(arr, el, index=0)
  while index < arr.length && arr[index] == el
    index += 1
  end

  index
end

def intersects(a, b)
  a.sort!
  b.sort!

  res = []
  i, j = 0, 0
  while i < a.length && j < b.length
    if a[i] == b[j]
      res << a[i]
      i = non_eq_index(a, a[i], i)
      j = non_eq_index(b, b[j], j)
    elsif a[i] < b[j]
      i += 1
    else
      j += 1
    end
  end
  res
end
Note
we need the auxillary method non_eq_index to skip past repeat occurences of the same number in the input arrays.