求因数的高效算法

今天在做leetcode周赛算法题的时候有一道关于求因数的题,正常的算法和求结果都已经做到了,但是对于一个大数据量的测试案例却始终无法通过,也就是时间复杂度不满足要求。后面思考的时候发现了这一类的题都可以把时间复杂度从O(n)降到O(\sqrt{n}).在这里记录一下方法。

题目是这样的:https://leetcode-cn.com/problems/four-divisors/

这题的普通解法是:

1.遍历数组中的每一个数。

2.对于每个数字,求它的所有因数,符合要求的相加。其中暴力做法求所有余数这一步骤需要O(n)

但是这样的解法没办法满足时间复杂的要求。对于求因数的这一个步骤,我们可以使用一种时间复杂度为O(\sqrt{n})的算法。

即只从 1开始,遍历到\sqrt{n}为止,其中n是每一个要被求余数的数字。因为如果n可以被一个小于\sqrt{n}的因子a整除,那么这个数一定有一个因数是大于\sqrt{n}的,它的值为b = n/a.

这样,我们就可以很轻易的写出我们的算法:

class Solution {
    public int sumFourDivisors(int[] nums) {
        int result = 0;     
        
        for(int e : nums)
        {
            int temp = 0;
            int cnt = 0;
            for(int i = 1; i * i <= e; i++)
            {
                if(e % i == 0)
                {
                    if(i * i == e)
                    {
                        cnt = 0;
                        break;
                    }
                    cnt += 2;
                    temp = temp + i + (e/i);
                }
            }
            if(cnt == 4)
                result += temp;
        }
        return result;
    }
}

这个算法中还有一个巧妙的点在于,如何这个数是一个平方数,那么它的因数个数一定为奇数,不满足题目要求,可以直接排除。这个算法的时间复杂度是O(n\sqrt{m}),其中n是数组长度,m是每一个数的大小。

猜你喜欢

转载自blog.csdn.net/qq_35824577/article/details/105028417