引言:
学习数据结构的第一步,就是要正确认识算法的时间效率质量,我们将其分为两个部分讨论:时间复杂度和空间复杂度。在日常使用中,我们通常只分析时间复杂度,并以此来选择合适的算法解决问题,并保证不会出现内存泄漏等问题即可。
下面对两道例题复杂度分析(Ⅰ)和复杂度(Ⅱ)的分析:
基础知识点:
在解这道题,我们先要了解一下循环嵌套:循环嵌套指的是在一个循环体内再包含一个或多个循环。其主要特点包括多层次的循环结构、外层循环控制内层循环、复杂度增加、内层循环频率高、变量作用域和广泛的应用场景,外层循环的每次迭代都会使内层循环重新执行一次,这使得循环嵌套在处理多维数据时非常有用。
问题 A: 复杂度分析(Ⅰ)
题目描述
分析如下代码
for(i=1;i<n;i++)
for(j=1;j<i;j++)
for(k=1;k<j;k++)
printf("\n");
问printf语句共执行了几次?这段代码执行完以后i+j+k值为多少?
输入
由多行组成,每行一个整数n, 1<= n <= 3000
输出
对每一行输入,输出对应的一行,包括空格分开的两个整数,分别代表printf语句的执行次数以及代码执行完以后i+j+k的值, 如果值不确定,输出"RANDOM"取代值的位置
样例输入
6
样例输出
10 15
思路分析:
由题分析可知,暴力求解必然会T,因为 n<=1000 ,复杂度为O(n^3),最坏情况是 1000^3,复杂度过高,所以需要对算法进行优化
分析代码
- 外层循环:
i
从1
到n-1
(共n-1
次)。 - 中层循环:
j
从1
到i-1
。 - 内层循环:
k
从1
到j-1
。
推导可得printf
的执行总次数是: 1,经过计算可得出公式为,
且在最后一轮循环下 i,j,k 的值分别为i=n
,j=i-1=n-1
,k=j-1=n-2
,所以 i+j+k 的值为 3n−3。注意特殊情况,当n<3时printf没有执行,输出“RANDOM”。
void solve()
{
int n;
while(cin >> n){
int cnt = (n-1) * (n-2)*(n-3)/6;
if( n >= 3)
cout << cnt << " " << 3*n-3 << endl;
else
cout << cnt << " " << "RANDOM" << endl;
}
}
问题 B: 复杂度分析(Ⅱ)
题目描述
有如下代码段(n为正整数):
i=1;
while(i++<n){
j=1;
while(j++<i){
k=1;
while(k++<j) printf("\n");
}
}
问printf语句共执行了几次?这段代码执行完以后i+j+k值为多少?
输入
由多行组成,每行一个整数n, 1<= n <= 3000
输出
对每一行输入,输出对应的一行,包括空格分开的两个整数,分别代表printf语句的执行次数以及代码执行完以后i+j+k的值, 如果值不确定,输出"RANDOM"取代值的位置。
样例输入
3
样例输出
4 12
思路分析:
大体思路如上,不同点在于循环次数不同于上道题的 n(n-1)(n-2),而是n*n*n;
分析代码
- 外层
while
循环:i
从1
到n
,执行n
次。 - 中层
while
循环:j
从1
到i
。 - 内层
while
循环:k
从1
到j
。
推导可得printf
的执行总次数是: 1,经过计算可得出公式为
且在最后一轮循环下 i,j,k 的值分别为i=n+1
,j=i=n+1
,k=j=n+1
所以 i+j+k 的值为 3(n+1)。注意特殊情况,当n<2时printf没有执行,输出“RANDOM”。
void solve()
{
int n;
while(cin >> n){
int cnt = (n+1) * (n-1)*n/6;
if( n >= 2)
cout << cnt << " " << 3*(n+1) << endl;
else
cout << cnt << " " << "RANDOM" << endl;
}
}