{x}
blog image

Two Out of Three

Given three integer arrays nums1, nums2, and nums3, return a distinct array containing all the values that are present in at least two out of the three arrays. You may return the values in any order.

 

Example 1:

Input: nums1 = [1,1,3,2], nums2 = [2,3], nums3 = [3]
Output: [3,2]
Explanation: The values that are present in at least two arrays are:
- 3, in all three arrays.
- 2, in nums1 and nums2.

Example 2:

Input: nums1 = [3,1], nums2 = [2,3], nums3 = [1,2]
Output: [2,3,1]
Explanation: The values that are present in at least two arrays are:
- 2, in nums2 and nums3.
- 3, in nums1 and nums2.
- 1, in nums1 and nums3.

Example 3:

Input: nums1 = [1,2,2], nums2 = [4,3,3], nums3 = [5]
Output: []
Explanation: No value is present in at least two arrays.

 

Constraints:

  • 1 <= nums1.length, nums2.length, nums3.length <= 100
  • 1 <= nums1[i], nums2[j], nums3[k] <= 100

Solution Explanation:

This problem asks us to find the numbers that appear in at least two out of three input arrays (nums1, nums2, nums3). The solution utilizes a frequency counting approach to efficiently identify these numbers.

Approach:

  1. Convert to Sets: The input arrays are converted into sets. Sets provide efficient membership testing (checking if an element exists within the set). This step eliminates duplicate numbers within each individual array, simplifying the subsequent counting process.

  2. Frequency Counting: The code iterates through numbers from 1 to 100 (inclusive, as specified in the constraints). For each number, it checks its presence in each of the three sets. This is typically done using in operator in Python, or contains method for sets in other languages.

  3. Condition Check: A counter is implicitly or explicitly used to keep track of the number of sets in which the current number is found. If this count is greater than or equal to 2, meaning the number is present in at least two arrays, it's added to the result array.

  4. Return Result: Finally, the function returns an array containing the unique numbers that satisfy the condition.

Time Complexity Analysis:

  • Converting to Sets: Converting each array to a set takes O(ni) time for each array, where ni is the length of the array. Therefore, the total time for this step is O(n1 + n2 + n3).
  • Iteration and Checking: The loop iterates 100 times (a constant). Inside the loop, checking the presence of a number in a set takes O(1) on average (using hash sets). The total time for this step is O(1) * 100, which is still O(1).
  • Overall: The dominant factor in the time complexity is the conversion to sets. Hence, the overall time complexity of the solution is O(n1 + n2 + n3).

Space Complexity Analysis:

  • Sets: Creating three sets requires space proportional to the number of unique elements in each array. In the worst case, this would be O(n1 + n2 + n3).
  • Result Array: The result array stores the numbers that appear in at least two arrays. In the worst-case scenario (all numbers from 1 to 100 are present in at least two arrays), this would take O(100) = O(1) space (constant space).
  • Overall: The overall space complexity is O(n1 + n2 + n3), dominated by the space used to store the sets.

Code Examples (with minor improvements):

The provided code snippets are already quite efficient. However, we can make minor improvements for clarity and consistency:

Python:

def twoOutOfThree(nums1: List[int], nums2: List[int], nums3: List[int]) -> List[int]:
    """Finds numbers present in at least two of three input arrays."""
    set1, set2, set3 = set(nums1), set(nums2), set(nums3)
    result = []
    for i in range(1, 101):  # Iterate through possible numbers
        count = (i in set1) + (i in set2) + (i in set3) #Efficient count
        if count >= 2:
            result.append(i)
    return result
 

Java:

import java.util.*;
 
class Solution {
    public List<Integer> twoOutOfThree(int[] nums1, int[] nums2, int[] nums3) {
        Set<Integer> set1 = new HashSet<>();
        for (int num : nums1) set1.add(num);
        Set<Integer> set2 = new HashSet<>();
        for (int num : nums2) set2.add(num);
        Set<Integer> set3 = new HashSet<>();
        for (int num : nums3) set3.add(num);
 
        List<Integer> result = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            int count = 0;
            if (set1.contains(i)) count++;
            if (set2.contains(i)) count++;
            if (set3.contains(i)) count++;
            if (count >= 2) result.add(i);
        }
        return result;
    }
}

Similar improvements can be applied to the other languages to make the code more readable and consistent. The core algorithm and complexity analysis remain the same.