Find pairs in two arrays such that when multiplied becomes a perfect square

后端 未结 4 823
不知归路
不知归路 2021-01-23 05:11

Given two integer arrays like this:-

int[] a = { 2, 6, 10, 13, 17,18 };
int[] b = { 3, 7, 8, 9, 11, 15 };

How can I find pai

相关标签:
4条回答
  • 2021-01-23 06:13

    Any two numbers where the count of each prime factor in the number is even, would form a valid pair. Otherwise, any number with an odd count of one or more prime factors could only pair with another number with the exact same factors having an odd count. This means all we would need to store for each number is which of its prime factors have an odd count. This could be hashed.

    a = { 2, 6, 10, 13, 17,18 }; 
    b = { 3, 7, 8, 9, 11, 15 };
    

    Hash the shorter array where the key is the combination of prime factors with odd count and the value is the corresponding list of indexes in the array:

    a = {
      2: [0,5],
      2-3: [1], 
      2-5: [2], 
      13: [3],
      17: [4]
    }
    

    Traverse the second array and exactly match the prime-factor-with-odd-count-combination:

    b[0] -> 3, no match
    b[1] -> 7, no match
    b[2] -> 2, match with a[0] and a[5] -> 2 * 8 and 18 * 8 are perfect squares
    b[3] -> None, no match
    b[4] -> 11, no match
    b[5] -> 3-5, no match
    
    0 讨论(0)
  • 2021-01-23 06:13

    I managed to simplify it using LINQ:

    int[] arr1 = { 2, 6, 10, 13, 17, 18 };
    int[] arr2 = { 3, 7, 8, 9, 11, 15 };
    int count = arr1.Sum(t => (from t1 in arr2 select t*t1 into x let s = (long) Math.Sqrt(x) where x == s*s select x).Count());
    
    0 讨论(0)
  • 2021-01-23 06:16

    For ordered (only matters for the detection of the max) arrays with integers > 0 with the help of a modified sieve of Eratosthenes, I think the complexity is O(max * log(max) * log(log(max)) + n) and there is O(max) extra space required (which can be a huge improvement or very bad depending on n and max compared to the standard O(n^2) with O(1) space and no dependency on max):

    long total = 0;
    int max = (a[a.length - 1] > b[b.length - 1] ? a[a.length - 1] : b[b.length - 1]) + 1;
    int[] sieve = new int[max], anti = new int[max], count = new int[max];
    for (int i = 1; i < max; i++) {
        sieve[i] = i; // using numbers and divide by prime instead of booleans
        anti[i] = 1; // number by which i has to be multiplied to get the smallest square
    }
    for (int i = 2; i < max; i++) {
        if (sieve[i] == i) { // i is prime
            for (int j = i; j < max; j += i) {
                boolean odd = false;
                do {
                    odd = !odd;
                    sieve[j] /= i;
                } while (sieve[j] % i == 0);
                if (odd)
                    anti[j] *= i;
            }
        } // if you know the max over all the calls the above has only to be done once
    } // except for resetting count and total, so we would get O(n) because max is constant
    for (int i = 0; i < a.length; i++)
        count[anti[a[i]]]++; // hash map for count is better than array if n < max
    for (int i = 0; i < b.length; i++)
        total += count[anti[b[i]]];
    

    A square number will be mapped to 1 and others to the product of primes with odd exponents in the factorization of the number. In your example every number is mapped to itself except for 8 => 2, 9 => 1, 18 => 2. Other interesting numbers below 18 (not square or mapping to itself): 12 => 3. When iterating over a the algorithm increases the count of 2 once when visiting 2 and once when visiting 18. The total will be increased by 2 when the iteration over b visits 8, the only matches between the two arrays and therefore the end result.

    0 讨论(0)
  • 2021-01-23 06:16

    I would check whether you have any decimal place after drawing the root left. If not then you have your perfect squareroot:

    void Main()
    {
        int[] arr1 = { 2, 6, 10, 13, 17, 18 };
        int[] arr2 = { 3, 7, 8, 9, 11, 15 };
    
        List<string> PairList = new List<string>();
    
        for (int i = 0; i < arr1.Length; i++)
        {
            for (int j = 0; j < arr2.Length; j++)
            {
                if (Math.Sqrt(arr1[i] * arr2[j]) % 1 == 0)
                {
                    PairList.Add(String.Format("{0} & {1}", arr1[i] , arr2[j]));
                }           
            }
        }
    
        PairList.Dump();
    }
    
    0 讨论(0)
提交回复
热议问题