问题:给定自然数N,如何求出N的所有约数?

如 N = 198,它的约数有:[1, 2, 3, 6, 9, 11, 18, 22, 33, 66, 99, 198]

 一个很自然的想法是:对从2到的所有数进行遍历,看这个数是否能整除N。这样的时间复杂度是

有没有更快一点的呢??

 我们可以这样考虑:如果有非平方数,其中,那么一定有,对于每一个小于的约数,都有一个对应的也是的约数,因此我们只需要遍历2到就可以了,每一次整除都对应了的两个约数,最后只需要再考虑一下是不是平方数就可以了。这样,时间复杂度就被优化到了,是个非常大的进步了。

下面贴代码

Python:

from typing import List

def divisors(N:int) -> List[int]:
    '''return all the factors of N'''
    if N == 1:
        return [1]
    res = [1, N]
    sqrt = int(pow(N, 1/2))
    for i in range(2, sqrt + 1):
        if N % i == 0:
            res.append(i)
            res.append(N // i)
    if sqrt ** 2 == N:
        res.append(sqrt)

    return res

print(sorted(divisors(198)))    
# [1, 2, 3, 6, 9, 11, 18, 22, 33, 66, 99, 198]

Java:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Divisors {
    public static List<Integer> divisors(int N) {
        List<Integer> res = new ArrayList<>();
        res.add(1);
        if (N == 1) return res;
        res.add(N);
        final int sqrt = (int) Math.sqrt(N);
        for (int i = 2; i < sqrt; i++) {
            if (N % i == 0) {
                res.add(N / i);
                res.add(i);
            }
        }
        if (sqrt * sqrt == N) res.add(sqrt);
        return res;
    }

    public static void main(String[] args) {
        List<Integer> res = divisors(198);
        // stream是Java 8的新语法
        System.out.println(Arrays.toString(res.stream().sorted().toArray()));
    }
}

C++

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

vector<int> divisors(int N) {
    vector<int> res{1};
    if (N == 1) return res;
    res.push_back(N);
    const int sq = sqrt(N);
    for (int i = 2; i <= sq; i++) {
        if (N % i == 0) {
            res.push_back(i);
            res.push_back(N / i);
        }
    }
    if (sq * sq == N) res.pop_back();  // sq 被计算了两遍
    return res;
}

int main() {
    vector<int> res = divisors(198);
    sort(res.begin(), res.end());
    for (auto n : res) {
        cout << n << " ";
    }
}