04 – 时间复杂度相关的题

一、常见题型

题目1、在数组A[0….n-1]中,查找给定值k的算法

// 题目1 在数组A中查找给定值k的算法
int main()
{
	int A[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 11;
	int i = sizeof(A) / sizeof(A[0]) - 1; //数组最后一个元素下标
	int count = 0; 

	while (i >= 0 && (A[i] != k))
	{
		count++;
		
		printf("i = %d , count = %d\n", i, count);

		i--;
	}
}

以下是代码运行结果

  • A中没有元素与k相等的元素,i– 运行的频度是f(n) = n
04 - 时间复杂度相关的题
  • A中最后一个元素与k相等,i– 运行的频度是f(n) = 0

题目2:计算下列代码的时间复杂度

void fun(int n)
{
	int i = 0;
	int count = 0;
	while (i * i * i <= n)
	{
		i++;
		count++;
		printf("i=%d ", i);
	}
	printf("\ncount=%d ", count);
}
int main()
{
	int n = 10;
	fun(n);
}

时间复杂度计算

  1. 关键操作:在while循环里,i进行自增操作,同时count也进行自增,并且执行printf函数。
  2. 循环终止条件:当i * i * i > n时,循环就会停止。
  3. 循环次数:假设循环执行的次数是k,那么i的值会从 0 开始,逐步增加到k。此时,k要满足k³ > n,而(k-1)³ ≤ n。由此可知,k的大小和 n 的立方根是同一个数量级,即k ≈ ∛n
  4. 时间复杂度:由于循环执行的次数和 n 的立方根成正比,所以该算法的时间复杂度为 O (∛n)。

结论

此算法的时间复杂度是O(n^(1/3))

以下是代码运行结果:

04 - 时间复杂度相关的题

题目3:冒泡排序 – 计算下列代码的最坏时间复杂度

#include <stdio.h>

int main()
{
    int i, j, temp;
    int A[] = {9,8,7,6,5,4,3,2,1,0};
    int count = 0;
    int sz = sizeof(A) / sizeof(A[0]);

    // 标准冒泡排序实现
    for (i = 0; i < sz - 1; i++) {
        for (j = 0; j < sz - i - 1; j++) {
            if (A[j] > A[j + 1]) {
                // 添加元素交换逻辑
                temp = A[j];
                A[j] = A[j + 1];
                A[j + 1] = temp;
                count++;
            }
        }
    }

    printf("count=%d\n", count);
    
    // 打印所有元素
    for (i = 0; i < sz; i++) {
        printf("%d ", A[i]);
    }
    printf("\n");

    return 0;
}

时间复杂度推导

  1. 外层循环次数: 变量 isz-1 递减到 2,共执行 n-2 次(假设 sz = n)。
  2. 内层循环次数: 对于每个 i,内层循环的次数为 i-1 次。具体来说:
    • i = n-1 时,内层循环执行 n-2 次;
    • i = n-2 时,内层循环执行 n-3 次;
    • i = 2 时,内层循环执行 1 次。
  3. 总执行次数: 内层循环的总次数为等差数列求和: 1 + 2 + 3 + … + (n-2) = (n-2)(n-1)/2展开后为 (n² – 3n + 2)/2,忽略低阶项和系数,时间复杂度为 O(n²)

关键结论

  • 无论输入如何,嵌套循环的结构决定了代码的执行次数始终是二次函数,因此最坏、平均和最好时间复杂度均为 O(n²)
  • 排序逻辑缺陷:尽管代码中的赋值操作(A[j] = A[j+1])无法正确排序数组,但时间复杂度仍由循环次数决定,与实际排序效果无关。

补充说明

  • 若要实现正确的冒泡排序,需在交换元素时同时更新 A[j+1](例如使用临时变量),但这不会改变时间复杂度。
  • 打印数组的循环(for (i = 0; i < sz - 1; i++))仅执行 n-1 次,时间复杂度为 O(n),但整体复杂度仍由嵌套循环主导(O (n²))。

题目4:另一种形式的冒泡排序

#include <stdio.h>

int main()
{
    int i, j, temp;
    int A[] = {9,8,7,6,5,4,3,2,1,0};
    int count = 0;
    int sz = sizeof(A) / sizeof(A[0]);

    // 修改:外层循环从 i=sz-1 开始递减到 1
    for (i = sz-1; i > 0; i--) {
        for (j = 0; j < i; j++) {
            if (A[j] > A[j + 1]) {
                temp = A[j];
                A[j] = A[j + 1];
                A[j + 1] = temp;
                count++;
            }
        }
    }

    printf("count=%d\n", count);
    
    // 打印所有元素
    for (i = 0; i < sz; i++) {
        printf("%d ", A[i]);
    }
    printf("\n");

    return 0;
}

1. 外层循环次数

  • 循环条件isz-1(数组末尾索引)递减到 1,共执行 n-1n 为数组长度,sz = n)。
  • 示例:当 n=10 时,i 取值为 9, 8, ..., 1,共循环 9 次。

2. 内层循环次数

  • 对于每个外层循环的 i,内层循环 j0 遍历到 i-1,执行 i
  • 次数规律:
    • i = n-1 时,内层循环执行 n-1 次;
    • i = n-2 时,内层循环执行 n-2 次;
    • ……
    • i = 1 时,内层循环执行 1 次。

3. 总操作次数(数学推导)

  • 内层循环总次数为等差数列求和:
04 - 时间复杂度相关的题
  • 最高阶项,忽略低阶项和系数后,时间复杂度为 O(n²)

4. 关键结论

场景时间复杂度说明
最坏情况O(n²)数组完全逆序(如示例输入),每轮均需完整比较和交换。
平均情况O(n²)随机无序数组,比较和交换次数接近最坏情况的一半。
最好情况O(n²)未优化时,即使数组有序,仍需执行所有比较(优化后可降至 O (n))。

最终结论

该冒泡排序代码的 最坏时间复杂度为 O (n²),由嵌套循环的二次方级操作次数决定。

实战题目

04 - 时间复杂度相关的题
04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题

数学解析
04 - 时间复杂度相关的题

题目5:计算下列m++代码执行次数

int main()
{
	int i = 0;
	int j = 0;
	int n = 10;
	int m = 0;

	for (i = 0;i <= n; i++)
	{
		for (j = 1;j <= 2 * i; j++)
		{
			m++;
		}
	}
	printf("m = %d\n", m);
}

以下是n=10计算结果:

04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

题目6:计算下列m++代码执行次数(对比题目5)

int main()
{
	int i = 0;
	int j = 0;
	int n = 10;
	int m = 0;

	for (i = 0;i < n;i++)
	{
		for (j = 1;j < 2 * i;j++)
		{
			m++;
		}
	}
	printf("m = %d\n", m);
}

以下是运行结果:

04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

(重要)总结以上该题型:

04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

题目7:计算递归函数的时间复杂度

// 题目 11:递归函数的时间复杂度
int Func(int n)
{
	if (n == 1)
		return 1;
	else
		return 2 * Func(n / 2) + n;
}

int main()
{
	int i = 4;
	int ret = Func(i);
	printf("%d\n", ret);
	return 0;
}

以下是运行结果:

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

数学表达

04 - 时间复杂度相关的题

二、408真题

题目1

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题

题目2

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

关键分析步骤:

  1. 递归调用次数:计算 fact(n) 时,会依次调用 fact(n-1)fact(n-2)、… 直到 fact(1)。总共有 n 次递归调用(从 n 递减到 1,共 n 层)。
  2. 每次调用的操作量:每次递归调用仅执行一次乘法运算(n * fact(n-1))和条件判断(n <= 1),均为常数时间 O(1)

结论

总时间复杂度为递归调用次数与单次操作时间的乘积,即:
时间复杂度 = O (n)(线性时间复杂度)。

题目3

04 - 时间复杂度相关的题
04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题

题目4

题目4

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题
int Func(int n)
{
	int i = 0; 
	int sum = 0;
	while (sum < n)
	{
		sum += ++i;
	}
	return sum;
}

int main()
{
	int n = 4;
	int ret = Func(n);
	printf("%d\n", ret);
	return 0;
}

要计算该代码的时间复杂度,我们需要分析Func函数中循环的执行次数与输入规模n的关系。

关键分析步骤:

  1. 循环逻辑while (sum < n) 循环中,sum 累加的是 ++i(即 i 先自增 1,再累加到 sum)。因此,循环的实际行为是计算从 1 开始的连续整数的累加和,直到累加和大于等于n
  2. 累加和公式:假设循环执行了k次,则累加和为 sum = 1 + 2 + 3 + ... + k = k(k+1)/2(等差数列求和公式)。
  3. 循环终止条件:循环终止时满足 sum >= n,即 k(k+1)/2 >= n。当n较大时,近似有 k² ≈ 2n,因此 k ≈ √(2n)kn的平方根成正比)。

时间复杂度结论:

循环的执行次数kn的平方根成正比,因此时间复杂度为 O(√n)(根号 n 阶)。

题目5

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题

题目6

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题
04 - 时间复杂度相关的题

题目7

04 - 时间复杂度相关的题
解析
04 - 时间复杂度相关的题

三、总结

04 - 时间复杂度相关的题

本网站原创文章版权归何大锤的狂飙日记所有。发布者:何大锤,转转请注明出处:何大锤的博客

(1)
何大锤的头像何大锤管理团队

相关推荐

  • C语言初阶 – 指针

    一、指针是什么? 指针是什么? 指针理解的2个要点: 1、指针是内存中一个最小单元(内存单元)的编号,也就是地址 2、平时口语中说的指针,通常是指针变量,用来存放内存地址的变量 总结:指针就是地址,口语中说的指针通常指的是指针变量 那么我们就这样理解:内存 指针变量 我们可以通过&(取地址操作符)取出变量的内存地址,把地址可以存放到一个变量中,这个变…

    2025年6月29日
    000
  • 09 通讯录管理系统

    通讯录管理系统 1、系统需求 通讯录是一个可以记录亲人、好友信息的工具。 本教程主要利用C++来实现一个通讯录管理系统 系统中需要实现的功能如下: 2、创建项目 创建项目步骤如下: 2.1 创建项目 打开vs2017后,点击创建新项目,创建新的C++项目 填写项目名称,选择项目路径 2.2添加文件 添加成功后,效果如图: 至此,项目已创建完毕 3、菜单功能 …

    2025年6月22日
    300
  • 08 结构体

    8 结构体 8.1 结构体基本概念 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型 8.2 结构体定义和使用 语法:struct 结构体名 { 结构体成员列表 }; 通过结构体创建变量的方式有三种: 示例: 总结1:定义结构体时的关键字是struct,不可省略 总结2:创建结构体变量时,关键字struct可以省略 总结3:结构体变量利用操作符 &…

    2025年6月21日
    300
  • 07 指针

    7.1 指针的基本概念 指针的作用: 可以通过指针间接访问内存 7.2 指针变量的定义和使用 指针变量定义语法: 数据类型 * 变量名; 示例: 指针变量和普通变量的区别 总结1: 我们可以通过 & 符号 获取变量的地址 总结2:利用指针可以记录地址 总结3:对指针变量解引用,可以操作指针指向的内存 7.3 指针所占内存空间 提问:指针也是种数据类型…

    2025年6月20日
    300
  • 第2章 C语言概述

    一、复习题 1、C语言的基本模块是什么? 它们都叫函数 2、什么是语法错误?写一个英语例子和C语言例子 3、什么是语义错误?写一个英语例子和C语言例子 4、Indiana Sloth编写了下面的程序,并征求你的意见。请帮助他评定 第一行没有加<> 赋值语句错误 函数错误应该是printf 花括号不齐全 二、编程练习 2.1 2.2 2.3 编写一…

    2025年6月20日
    000

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

2211932694

在线咨询: QQ交谈

邮件:hdcblog1999@163.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
网站建设中ing......