简体   繁体   中英

Math explanation of why this code works

I encountered a problem in the site CodeFights that I resolved with two loops. While looking at other answer I found one that resolved it with no loops and it left me with my mouth open. The coder applied Math.min/max , and while I do understand what the code does I don't understand why it works.

I've love to learn because heck, Math.max/min beats the bytes out of my loops for sure.

Given integers n, l and r, find the number of ways to represent n as a sum
of two integers A and B such that l ≤ A ≤ B ≤ r.

Example

For n = 6, l = 2 and r = 4, the output should be
countSumOfTwoRepresentations2(n, l, r) = 2.

There are just two ways to write 6 as A + B, where 2 ≤ A ≤ B ≤ 4: 6 = 2 + 4 and 6 = 3 + 3.

Input/Output

[time limit] 4000ms (js)
[input] integer n

A positive integer.

Constraints:
5 ≤ n ≤ 109.

[input] integer l

A positive integer.

Constraints:
1 ≤ l ≤ r.

[input] integer r

A positive integer.

Constraints:
l ≤ r ≤ 109,
r - l ≤ 106.

The coder's amazing answer:

function countSumOfTwoRepresentations2(n, l, r) {
    return Math.max(Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1, 0);
}

My crap in comparison:

function countSumOfTwoRepresentations2(n, l, r) {
    var representations = 0;
    //Only travel the loop until n/2 , because l+r will never equal n
    // if l or r > n/2
    var limit = Math.floor(n/2);
    for(var i=l; i<=r && i<=limit; ++i){
        for(var j=i;j<=r;++j){ 
            if(i+j == n){
                ++representations;
                break; 
            }
        }
    }
    return representations;
}

Given integers n , l and r , find the number of ways to represent n as a sum of two integers A and B such that l ≤ A ≤ B ≤ r .

First, consider that if n is even and letting x = n/2 , we have at least one solution ( x + x ) if, and only if, l ≤ x ≤ r . If x isn't in that range then there is no solution, since either x < l and l + l > n or r < x and r + r < n .

That can be generalized to even or odd n : There is a solution if, and only, if: l ≤ floor(x) ≤ ceil(x) ≤ r . If we let A = floor(x) and B = ceil(x) , that solution is A + B . Every other solution can be found by taking one step along the number line away from that point in each direction. (A - 1) + (B + 1) = A + B = n , therefore (A - 1) + (B + 1) is a solution as long as (A - 1) hasn't crossed the l boundary and (B + 1) hasn't crossed the r boundary. So, if you wanted a solution with only one loop, you could do something like this:

function countSumOfTwoRepresentations2(n, l, r) {
    var x = n/2;
    var A = Math.floor( x );
    var B = Math.ceil( x );
    for ( var count = 0; l <= A && B <= r; count++) {
        A--;
        B++;
    }
    return count;
}

But how many times does that loop iterate? Well, it iterates until one of the stopping conditions happens:

  1. A becomes smaller than l
  2. B becomes larger than r

If 1. happens first, then it iterates Math.floor( x ) - l + 1 times, whereas if 2. happens first it iterates r - Math.ceil( x ) + 1 (if both conditions happen on the same iteration, then Math.floor( x ) - l === r - Math.ceil( x ) ).

As long as there is a solution the loop iterates the smaller of Math.floor( x ) - l + 1 or r - Math.ceil( x ) + 1 times, which is where the coder got the answer Math.min(Math.floor(n / 2) - l, r - Math.ceil(n / 2)) + 1 from (after substituting x back for n/2 and pulling the + 1 out of each term and adding it after instead.

If there is no solution, EG. n = 10, l = 20, r = 20 EG. n = 10, l = 20, r = 20 , that formula will give a negative result, but it should give 0 instead, which is why he added Math.max( result, 0 ); .

For clarity, the coder's solution could be written as (still with no loops):

function countSumOfTwoRepresentations2(n, l, r) {
    var x = n/2;
    var A = Math.floor( x );
    var B = Math.ceil( x );

    // Every solution is of the form (A - i) + (B + i), where i is an integer >= 0

    // How many values of i are valid for l <= (A - i)
    var stepsA = A - l + 1;

    // How many values of i are valid for (B + i) <= r
    var stepsB = r - B + 1;

    // If the formulas gave a negative amount of valid steps, 
    // there is no solution, so return 0
    if ( stepsA < 0 || stepsB < 0 )
        return 0;

    // Otherwise, return the smaller valid amount of steps,
    // that is the number of steps that are valid for both A and B
    return Math.min(stepsA, stepsB);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM