【代码随想录笔记】 1.2 算法性能分析 -- 递归算法的时间复杂度

递归算法的时间复杂度: 递归的次数 * 每次递归中的操作次数。

例1

int function1(int x, int n) {
	int result = 1;  // 注意 任何数的0次方等于1
	for (int i = 0; i < n; i++) {
		result = result * x;
	}
	return result;
}

通常思路,时间复杂度O(n)。

例2

int function2(int x, int n) {
	if (n == 0) {
		return 1; // return 1 同样是因为0次方是等于1的
	}
	return function2(x, n - 1) * x;
}

每次n-1,递归了n次时间复杂度是O(n),每次进行了一个乘法操作,乘法操作的时间复杂度一个常数项O(1),所以这份代码的时间复杂度是 n × 1 = O(n)。

例3

int function3(int x, int n) {
	if (n == 0) {
		return 1;
	}
	if (n % 2 == 1) {
		return function3(x, n / 2) * function3(x, n / 2)*x;
	}
	return function3(x, n / 2) * function3(x, n / 2);
}

上述算法可以用一棵满二叉树来表示(为了方便表示,选择n为偶数16),如图:
image
(勘误,上图中的n*n应该替换为x*x)

当前这棵二叉树就是求x的n次方,n为16的时候,进行了多少次乘法运算呢?

这棵树上每一个节点就代表着一次递归并进行了一次相乘操作,所以进行了多少次递归的话,就是看这棵树上有多少个节点。(想象成16个数,每次对半分,到叶子节点就只剩2个数,直接相乘无需再分)

熟悉二叉树话应该知道如何求满二叉树节点数量,这棵满二叉树的节点数量就是2^3 + 2^2 + 2^1 + 2^0 = 15,可以发现:这其实是等比数列的求和公式,这个结论在二叉树相关的面试题里也经常出现。

那么,如果是求x的n次方,这个递归树有多少个节点呢,如下图所示:(m为深度,从0开始)
image

时间复杂度忽略掉常数项-1之后,这个递归算法的时间复杂度依然是O(n)。

例4 -- 时间复杂度为O(logn)

int function4(int x, int n) {
    if (n == 0) {
        return 1;
    }
    int t = function4(x, n / 2);// 这里相对于function3,是把这个递归操作抽取出来
    if (n % 2 == 1) {
        return t * t * x;
    }
    return t * t;
}

这里仅仅有一个递归调用,且每次都是n/2 ,所以这里我们一共调用了log以2为底n的对数次。

每次递归了做都是一次乘法操作,这也是一个常数项的操作,那么这个递归算法的时间复杂度才是真正的O(logn)。

posted @ 2022-04-29 11:36  围城chen  阅读(74)  评论(0编辑  收藏  举报