Finding pairs with product greater than sum

前端 未结 5 1996
长发绾君心
长发绾君心 2020-12-13 22:04

Given as input, a sorted array of floats, I need to find the total number of pairs (i,j) such as A[i]*A[j]>=A[i]+A[j] for each i < j

相关标签:
5条回答
  • 2020-12-13 22:13

    Here's an O(n) algorithm.

    Let's look at A * B >= A + B.

    • When A, B <= 0, it's always true.

    • When A, B >= 2, it's always true.

    • When A >= 1, B <= 1 (or B >= 1, A <= 1), it's always false.

    • When 0 < A < 1, B < 0 (or 0 < B < 1, A < 0), it can be either true or false.

    • When 1 < A < 2, B > 0 (or 1 < B < 2, A > 0), it can be either true or false.

    Here's a visualization, courtesy of Wolfram Alpha and Geobits:

    Now, onto the algorithm.

    * To find the pairs where one number is between 0 and 1 or 1 and 2 I do something similar to what is done for the 3SUM problem.

    * "Pick 2" here is referring to combinations.

    • Count all the pairs where both are negative

      Do a binary search to find the index of the first positive (> 0) number - O(log n).

      Since we have the index, we know how many numbers are negative / zero, we simply need to pick 2 of them, so that's amountNonPositive * (amountNonPositive-1) / 2 - O(1).

    • Find all the pairs where one is between 0 and 1

      Do a binary search to find the index of the last number < 1 - O(log n).

      Start from that index as the right index and the left-most element as the left index.

      Repeat this until the right index <= 0: (runs in O(n))

      • While the product is smaller than the sum, decrease the left index

      • Count all the elements greater than the left index

      • Decrease the right index

    • Find all the pairs where one is between 1 and 2

      Do a binary search to find the index of the first number > 1 - O(log n).

      Start from that index as the left index and the right-most element as the right index.

      Repeat this until the left index >= 2: (runs in O(n))

      • While the product is greater than the sum, decrease the right index

      • Count all the elements greater than the right index

      • Increase the left index

    • Count all the pairs with both numbers >= 2

      At the end of the last step, we're at the first index >= 2.

      Now, from there, we just need to pick 2 of all the remaining numbers,
      so it's again amountGreaterEqual2 * (amountGreaterEqual2-1) / 2 - O(1).

    0 讨论(0)
  • 2020-12-13 22:17

    Here's a O(n) algorithm that solves the problem when the array's elements are positive.

    When the elements are positive, we can say that:

    • If A[i]*A[j] >= A[i]+A[j] when j>i then A[k]*A[j] >= A[k]+A[j] for any k that satisfies k>i (because the array is sorted).

    • If A[i]*A[j] < A[i]+A[j] when j>i then A[i]*A[k] < A[i]+A[k] for any k that satisfies k<j.

    (these facts don't hold when both numbers are fractions, but then the condition won't be satisfied anyway)

    Thus we can perform the following algorithm:

    int findNumOfPairs(float A[])
    {    
        start = 0;
        end = A.length - 1;
        numOfPairs = 0;
    
        while (start != end)
        {
            if (A[start]*A[end] >= A[start]+A[end])
            {
                numOfPairs += end - start;
                end--;
            }
            else
            {
                start++;
            }
        }
    
        return numOfPairs;
    }
    
    0 讨论(0)
  • 2020-12-13 22:20

    You can find and print the pairs (in a shorthand form) in O(n log n).

    For each A[i] there is a minimum number k that satisfies the condition(1). All values greater than k will also satisfy the condition.

    Finding the lowest j such that A[j] >= k using binary search is O(log n).

    So you can find and print the result like this:

    (i, j)
    (1, no match)
    (2, no match)
    (3, >=25)
    (4, >=20)
    (5, >=12)
    (6, >6)
    (7, >7)
    ...
    (n-1, n)       
    

    If you want to print all combinations, then it is O(n^2), because the number of combinations are O(n^2).

    (*) To handle negative numbers it actually needs to be a bit more complex, because the numbers that satify the equation can be more that one range. I'm not absolutely sure how it behaves for small negative numbers, but if the number of ranges is not absolutely limited then my solution is no longer better than O(n^2).

    0 讨论(0)
  • 2020-12-13 22:21

    Here's a binary search, O(n log n):

    There's a breaking point for each number at A*B = A+B. You can reduce this to B = A / (A - 1). All numbers on one side or the other will fit it. It doesn't matter if there are negative numbers, etc.

    • If A < 1, then all numbers <= B fit.

    • If A > 1, then all numbers >= B fit.

    • If A == 1, then there is no match(divide by zero).

    (Wolfram Alpha link)


    So some pseudocode:

    loop through i
        a = A[i]
        if(a == 1)
            continue
        if(a >= 2)
            count += A.length - i 
            continue
    
        j = binsearch(a / (a-1))
    
        if(j <= i)
            continue
    
        if(a < 1)
            count += j-i
        if(a > 1)
            count += A.length - j
    
    0 讨论(0)
  • 2020-12-13 22:35

    How about excluding all floats that less then 1.0 first, since any number multiple with number less than 1, the x*0.3=A[i]+A[j] for each i < j, so we only need to count numbers of array to calculate the number of pairs(i, j), we can use formula about permutation and combination to calculate it. formula should be n(n-1)/2.

    0 讨论(0)
提交回复
热议问题