简体   繁体   中英

How can I reduce the time complexity of the following block of code?

I am taking 1 to n digits and finding count of numbers that are divisible by a or b but not divisible by both. I want to reduce time complexity of this block by some logical change.

cin >> n >> a >> b >> k;      
for(int i = 1; i <= n; i++) {
    if(i % a == 0 && i % b==0) {
        count++;
    } else if(i % b == 0 && i % a != 0) {
        count++;
    }
}

Calculate the count of numbers divisible by a, add it to the count of numbers divisible by b, subtract it with twice the count of numbers divisible by the lcm (lowest common multiple) of a,b.

Time complexity: O(log(min(a,b)))

Because to calculate Lowest common multiple you calculate gcd (Greatest common divisor) which can be calculated in O(log(min(a,b)))

Note: If you include bits/stdc++.h , you can use the inbuilt function to calculate gcd: __gcd(int , int )

int lcm(int a, int b) {
        return (a * b)/__gcd(a,b);
    }

cin>>n>>a>>b>>k;

int divisible_by_a = n / a;
int divisible_by_b = n / b;
int divisible_by_both = n / lcm(a,b);

ans = divisible_by_a + divisible_by_b - 2*divisible_by_both;

It seems to me that your code don't work as you describe: it counts for every number divisible by b . You should check if i is multiple of a or b

if (i % a == 0 && i % b != 0) {...
} else if (i % a != 0 && i % b == 0) {...
}

I also suggest to you a different approach: find multiples of a and b untill you reach n and count that numbers. remove same numers in lists from the sum (better if you do that before the final sum)

Before optimizing it, make sure it works first.

Right now, you're checking if a number is divisible by only b or by both a and b . To make it a or b but not both, you need to switch i % b==0 to i % b!=0 in the first condition:

for(int i = 1; i <= n; i++) {
    if(i % a == 0 && i % b!=0) {
        count++;
    } else if(i % b == 0 && i % a != 0) {
        count++;
    }
}

One small thing you can do to speed things up is to do the divisibility check just once each and save the result instead of twice. Then you can use a single XOR for the final result.

for(int i = 1; i <= n; i++) {
    int div_a = (i % a == 0);
    int div_b = (i % b == 0);

    if (a ^ b) {
        count++;
    }
}

Let's start with this:

    temp = a;
    while(temp < n) {
        if(temp%b != 0) {
            count++;
        }
        temp += a;
    }
    temp = b;
    while(temp < n) {
        if(temp%a != 0) {
            count++;
        }
        temp += b;
    }

Next, consider some cheats. If a%b == 0 then any number divisible by a will also be divisible by b ; and similar for b%a == 0 . In both cases the count must be zero.

If a == 0 then no number is divisible by a ; and similar for b == 0 ; and if both a and b are zero then the count must be zero.

Finally; don't forget that (in C) the behavior of x%0 is undefined and you need to guard against that.

Combining all of the above you get something like:

    if( (a == 0) && (b == 0) ) {
        return 0;
    }
    if( (a != 0) && (b != 0) ) {
        if( (a%b == 0) || (b%a == 0) ) {
            return 0;
        }
    }

    count = 0;
    if(a != 0) {
        temp = a;
        while(temp < n) {
            if(temp%b != 0) {
                count++;
            }
            temp += a;
        }
    }
    if(b != 0) {
        temp = b;
        while(temp < n) {
            if(temp%a != 0) {
                count++;
            }
            temp += b;
        }
    }
    return count;

Next round of cheats:

  • If n <= 1 then the count must be zero.
  • If a == 1 or a == -1 then all numbers are divisible by a .
  • If b == 1 or b == -1 then all numbers are divisible by b .

To deal with these I'd move to "nested switch" to minimise the number of branches, like:

switch(a) {
    case 0:
        switch(b) {
            case 0:
                ...
                break;
            case -1:
            case 1:
                ...
                break;
            default:
                ...
                break;
        }
        break;
    case -1:
    case 1:
        switch(b) {
            case 0:
                ...
                break;
            case -1:
            case 1:
                ...
                break;
            default:
                ...
                break;
        }
        break;
    default:
        switch(b) {
            case 0:
                ...
                break;
            case -1:
            case 1:
                ...
                break;
            default:
                ...
                break;
        }
        break;
}

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