如何减少以下代码块的时间复杂度?

时间:2019-02-03 15:47:06

标签: c++ algorithm if-statement time-complexity

我正在获取1到n个数字,并找到可以被a或b整除但不能被两者整除的数字计数。 我想通过一些逻辑上的更改来减少此块的时间复杂度。

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++;
    }
}

4 个答案:

答案 0 :(得分:4)

计算可被a整除的数字计数,将其加到可被b整除的数字计数上,再减去可被a,b的lcm(最小公倍数)整除的数字计数的两倍。

时间复杂度:O(log(min(a,b)))

由于要计算最低公倍数,因此计算出gcd(最大公除数),可以在O(log(min(a,b)))中计算

注意:如果包含bits/stdc++.h,则可以使用内置函数来计算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;

答案 1 :(得分:0)

在我看来,您的代码无法按照您所描述的那样工作:它被b整除的每个数字都计数。您应该检查我是a还是b的倍数

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

我还建议您使用另一种方法:找到ab的倍数,直到达到n并计算该数字。从总和中删除列表中的相同数字(最好在最终总和之前删除)

答案 2 :(得分:0)

在对其进行优化之前,请确保它首先起作用。

现在,您正在检查一个数字是否只能被lambda=0两者 ba整除。要使其ba但不能同时使用两者,您需要在第一种情况下将b切换为i % b==0

i % b!=0

您可以做的一件小事就是加快检查速度,并只将结果保存一次,而不是保存两次。然后,您可以将单个XOR用于最终结果。

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

答案 3 :(得分:0)

让我们从这里开始:

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

接下来,考虑一些作弊。如果a%b == 0,那么任何a可整除的数字也将被b除整;与b%a == 0类似。在两种情况下,计数都必须为零。

如果a == 0不能被a整除;与b == 0类似;并且如果ab均为零,则计数必须为零。

最后;别忘了({C}中x%0的行为是不确定的,您需要注意这一点。

结合以上所有内容,您将获得类似的信息:

    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;

下一轮作弊:

  • 如果n <= 1,则计数必须为零。
  • 如果a == 1a == -1,则所有数字都可以被a整除。
  • 如果b == 1b == -1,则所有数字都可以被b整除。

要处理这些问题,我将转到“嵌套开关”以最小化分支的数量,例如:

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;
}