时间复杂度的计算技巧-算法模型中的时间复杂度如何计算,有哪些技巧呢

news2024/11/27 17:53:37

大家好,我是微学AI,今天给大家介绍一下时间复杂度的计算技巧-算法模型中的时间复杂度如何计算,有哪些技巧呢,算法的时间复杂度是评估算法性能和效率的一种方式,它表示算法需要执行多少次基本操作才能完成其任务,这个数量随着输入规模的增加而增加。
时间复杂度通常用大O符号表示,例如O(n)、O(n²)等。其中,n表示输入规模,也就是算法需要处理的数据的大小。
在这里插入图片描述

一、常见的时间复杂度有:

O(1):常数时间复杂度,表示算法的执行时间不随输入规模的增加而增加,例如数组的索引访问。
O(log n):对数时间复杂度,表示算法的执行时间随着输入规模的增加而增加,但增加速度很慢,例如二分查找。
O(n):线性时间复杂度,表示算法的执行时间随着输入规模的增加而线性增加,例如遍历数组。
O(n log n):线性对数时间复杂度,表示算法的执行时间随着输入规模的增加而略微超线性增加,例如快速排序。
O(n²):平方时间复杂度,表示算法的执行时间随着输入规模的增加而平方级别增加,例如冒泡排序。

对于同一问题,不同的算法可能具有不同的时间复杂度,因此在选择算法时需要综合考虑时间复杂度、空间复杂度以及算法的实现难度等因素。

二、在C语言中的算法时间复杂度

我们可以通过对程序执行的次数的统计来计算其时间复杂度。一般情况下,我们关注的是最坏情况下程序的执行次数,因为最坏情况下的时间复杂度往往是算法的瓶颈。

对于一个基本操作(如赋值、比较、运算等),我们假设其执行时间为常量单位时间(即 O(1) 时间复杂度)。那么我们可以根据程序的代码结构和控制流程,计算出程序在最坏情况下的执行次数,从而确定其时间复杂度。下面是一些常见的时间复杂度及其示例:

  1. O(1) 常数级别
int a = 1;
int b = 2;
int c = a + b;

上述代码中,三个赋值语句和一个加法运算都是 O(1) 操作,总的时间复杂度也是 O(1)。

  1. O(n) 线性级别
for (int i = 0; i < n; i++) {
    printf("%d ", i);
}

上述代码中,for 循环中的 printf 语句会被执行 n 次,因此总的时间复杂度是 O(n)。

  1. O(n^2) 平方级别
for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        printf("%d ", i + j);
    }
}

上述代码中,内层循环中的 printf 语句会被执行 n^2 次,因此总的时间复杂度是 O(n^2)。

  1. O(log n) 对数级别
int i = n;
while (i > 0) {
    printf("%d ", i);
    i /= 2;
}

上述代码中,while 循环的条件是 i > 0,每次循环 i 会被除以 2,因此循环执行的次数为 log2(n)+1(以 2 为底的对数),因此总的时间复杂度是 O(log n)。

  1. O(n log n) 线性对数级别
for (int i = 0; i < n; i++) {
    int j = n;
    while (j > 0) {
        printf("%d ", i + j);
        j /= 2;
    }
}

上面代码中,外层循环会被执行 n 次,内层循环会被执行 log2(n)+1 次,因此总的时间复杂度是 O(n log n)。

计算时间复杂度时,一般采用大 O 记法,去掉常数项和低次项,只保留最高次项。另外,在计算时间复杂度时,需要注意以下几点:

  1. 循环嵌套时,内层循环次数的上界应该是外层循环的变量。
  2. 递归算法的时间复杂度需要进行递推处理,通常会使用主定理或递归树等方法。
  3. 位运算、矩阵乘法等特殊运算的时间复杂度需要特别处理。

三、递归算法的时间复杂度(python)

当涉及递归算法的时间复杂度时,有几种常见的复杂度级别。下面我将为你提供每种级别的例子代码:

  1. O(1) 常数级别的递归算法
def recursive_constant(n):
    if n <= 0:
        return
    print("Hello!")
    recursive_constant(n - 1)

上述代码中,无论输入是多少,函数都只会递归调用自身一次,因此时间复杂度为 O(1)。

  1. O(n) 线性级别的递归算法
def recursive_linear(n):
    if n <= 0:
        return
    print(n)
    recursive_linear(n - 1)

上述代码中,递归调用的次数与输入规模 n 成线性关系,因此时间复杂度为 O(n)。

  1. O(n^2) 平方级别的递归算法
def recursive_quadratic(n):
    if n <= 0:
        return
    for i in range(n):
        print(n)
    recursive_quadratic(n - 1)

上述代码中,递归调用的次数与输入规模 n 成平方关系,这个函数的时间复杂度是O(n^2),其中n表示输入的参数值。

我们来分析一下:

该函数是一个递归函数,每次递归调用都会执行一个for循环,循环次数为n。然后,递归调用将参数n减1,并再次执行相同的操作。

因此,在第一次递归调用中,for循环会执行n次。在第二次递归调用中,for循环会执行n-1次,以此类推,直到n减少到1为止。

总的执行次数可以近似为n + (n-1) + (n-2) + … + 1。根据等差数列求和公式,可以得到:

n + (n-1) + (n-2) + … + 1 = (n+1) * n / 2

因此,总的执行次数约为(n+1) * n / 2,也就是O(n^2)。

  1. O(2^n) 指数级别的递归算法
def recursive_exponential(n):
    if n <= 0:
        return
    print(n)
    recursive_exponential(n - 1)
    recursive_exponential(n - 1)

这个函数的时间复杂度是O(2^n),其中n表示输入的参数值。让我们来分析一下:

该函数是一个递归函数,每次递归调用都会执行两个递归调用。在每个递归调用中,参数n都会减1,并再次执行相同的操作。

因此,在第一次递归调用中,函数会执行一次print语句和两次递归调用。在第二次递归调用中,每次递归调用又会执行一次print语句和两次递归调用。以此类推,直到n减少到0为止。

总的执行次数可以近似为2^0 + 2^1 + 2^2 + … + 2^n。根据等比数列求和公式,可以得到:

2^0 + 2^1 + 2^2 + … + 2^n = 2^(n+1) - 1

因此,总的执行次数约为2^(n+1) - 1,也就是O(2^n)。

需要注意的是,递归函数的空间复杂度是O(n),因为每次递归调用都会在内存中创建新的函数调用栈。

四、 O(nlogn)与O(n^2logn)的时间复杂度:

1.O(nlogn)的例子

def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    
    # 分割数组
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    
    # 合并并排序子数组
    return merge(left, right)

def merge(left, right):
    merged = []
    i, j = 0, 0
    
    # 依次比较两个子数组的元素,并按顺序合并
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1
    
    # 将剩余的元素添加到合并后的数组中
    merged.extend(left[i:])
    merged.extend(right[j:])
    
    return merged

arr = [4, 2, 7, 1, 5, 3]
sorted_arr = merge_sort(arr)
print(sorted_arr)

以上示例使用归并排序算法对一个数组进行排序,归并排序的时间复杂度为O(nlogn)。在每次递归中,数组会被分割成两半,每一层递归需要O(n)的时间复杂度来合并两个已排序的子数组。

  1. O(n^2logn)的例子:
def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        
        # 在已排序的子数组中找到合适的位置插入元素
        while j >= 0 and arr[j] > key:
            arr[j+1] = arr[j]
            j -= 1
        
        arr[j+1] = key

def nested_insertion_sort(arr):
    for i in range(len(arr)):
        insertion_sort(arr)
    
    return arr

arr = [4, 2, 7, 1, 5, 3]
sorted_arr = nested_insertion_sort(arr)
print(sorted_arr)

以上使用嵌套的插入排序算法对一个数组进行排序,其中外层循环对数组进行n次插入排序,而插入排序的时间复杂度为O(n^2)。 因此,整个算法的时间复杂度为 O(n^2 logn)。每次插入排序都需要O(n^2)的时间复杂度,而总共需要进行logn次插入排序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1166800.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库】关系数据库管理系统 (RDBMS) 中事务处理的四个特性ACID

给自己一个目标&#xff0c;然后坚持一段时间&#xff0c;总会有收获和感悟&#xff01; 数据库事务是指一组数据库操作&#xff08;例如插入、更新、删除等&#xff09;&#xff0c;被视为一个单独的逻辑操作单元&#xff0c;并且要么全部执行成功&#xff0c;要么全部不执行&…

Eolink Apikit 如何对所有 API 异常请求实时监控 ?

API 监控适合业务在互联网上&#xff0c;并且用户来自多个不同的地区&#xff0c;且对API的要求较高的场合&#xff0c;用于解决以下的问题&#xff1a; 发现由于网络中断或者是API响应异常等导致的服务不可用 及时对异常的API进行告警 记录监控的日志&#xff0c;方便排查 …

基于Jaccard相似度的推荐算法---示例

目录 数据展示推荐算法的分类基于相似度基于流行度/上下文/社交网络 Jaccard相似度分析数据的特点可以考虑的方法计算方法优缺点计算用户之间的Jaccard相似度获取与给定最相似的10个用户对1713353的用户推荐10本书 数据展示 import pandas as pd import numpy as np# 读取CSV文…

vue+elementUI 设置el-descriptions固定长度并对齐

问题描述 对于elementUI组件&#xff0c;el-descriptions 在以类似列表的形式排列的时候&#xff0c;上下无法对齐的问题。 问题解决 在el-descriptions 标签中&#xff0c;添加属性&#xff1a; :contentStyle"content_style" 控制其内容栏长度 <el-descripti…

Visual Components Robotics OLP解决方案 北京衡祖

Visual Components 引入了“Visual Components Robotics OLP”的重大升级&#xff0c;合并了制造模拟和机器人离线编程。该解决方案利用 Delfoi Robotics 的技术&#xff0c;提高生产率、减少停机时间并减少浪费。 一、探索下一代离线机器人编程软件 自 1999 年以来&#xff0…

强大的pdf编辑软件:Acrobat Pro DC 2023中文

Acrobat Pro DC 2023是一款强大的PDF编辑和管理软件&#xff0c;它提供了广泛的功能&#xff0c;使用户能够轻松创建、编辑、转换和共享PDF文档。通过直观的界面和先进的工具&#xff0c;用户可以快速进行文本编辑、图像调整、页面管理等操作&#xff0c;同时支持OCR技术&#…

MobPush自定义智能标签,赋能精细化运营

随着用户兴趣爱好日益多元化&#xff0c;如何精准把握用户喜好&#xff0c;向用户定制推送用户所喜好的内容&#xff0c;成为APP能否提升用户粘性和活跃度&#xff0c;形成竞争力的关键。 因此&#xff0c;MobPush此前全面上新了”智能标签“功能&#xff0c;成为无数APP运营者…

图形化ping工具gping

一、介绍 gping能够以折线图的方式&#xff0c;实时展示 ping 的结果&#xff0c;支持 Windows、Linux 和 macOS 操作系统。并且支持多个目标同时Ping同时展示折线图方便对比。下面扩展一下ICMP及ICMP隧道。 ICMP消息结构&#xff1a; ICMP消息是由一个类型字段、一个代码字段、…

数据结构——顺序表(SeqList)

目录 1. 顺序表介绍 2. 顺序表工程 2.1 顺序表定义 2.1.1 静态顺序表 2.1.2 动态顺序表 2.2顺序表接口 2.2.1 顺序表初始化 2.2.2 顺序表打印 2.2.3 顺序表销毁 2.2.4 顺序表数据插入 2.2.4.1 容量检查 2.2.4.2 顺序表尾插 2.2.4.3 顺序表头插 2.2.4.4 顺序表随机…

Vue Vuex的使用和原理 专门解决共享数据的问题

Vuex专门解决共享数据的问题 多组件共享时使用&#xff0c;如用户ID各组件需要根据ID发送请求获取数据&#xff0c;任意组件可以进行增删改&#xff0c;相当于全局变量 Vuex 工作流程 如果确定值参数可以不经过Actions 直接走 安装Vuex vue2使用 vuex3 vue3使用 vuex4 npm i…

服务Service

一、服务概述 Service(服务)是Android四大组件之一&#xff0c;是能够在后台长时间执行操作并且不是供用户界面的应用程序组件。Senice可以与其他组件进行交互&#xff0c;一般由Activity启动&#xff0c;但是并不依赖于Activity。当Activity的生命周期结束时&#xff0c;Serv…

UNI-APP_ios自动适应底部安全区背景,修改安全区背景

自动适应&#xff08;推荐&#xff09; 将所有 iPhone X&#xff08;刘海屏) 底部安全区域背景颜色 自动适应&#xff0c;当前页面什么颜色会自动调整。 1.打开 manifest.json &#xff0c;打开源码视图 2.找到 app-plus 配置项&#xff0c;添加以下代码 "safearea&quo…

vue的message提示信息修改提示框所在页面位置高度

vue的message提示信息修改提示框所在页面位置高度&#xff0c;可以使用message的offset属性通过数值来改变提示框位置&#xff01; html部分代码 <div><el-button type"primary" click"showMessage" style"margin-left:40%;margin-top:1%&q…

Python多线程和代理请求示例

这是一个python多线程调用和代理提交的示例 可以用于负载均衡测试和高并发测试 import hashlib import json import random import sys import threading import time import requests as requests from requests.packages.urllib3.exceptions import InsecureRequestWarningr…

windows jar包文件默认打开方式设置

1、管理员权限打开“注册表编辑器”&#xff1b; 2、定位到计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts项下&#xff0c;找到.jar项&#xff0c;再选中UserChoice项&#xff0c;其中ProgId值为jarfile 3、定位到计算机\HKEY_CLAS…

Pixhawk2.4.8接口及引脚定义

pixhawk2.4.8实物图 pixhawk侧边信号线插口 遥控器接收机、电调信号线插在这里 pixhawk侧边功能口 Micro-USB接口用来烧录固件、SD卡中有飞行日志等信息 pixhawk主面板接口 主面板接口功能概览 主面板接口定义 参考博客&#xff1a; https://zhuanlan.zhihu.com/p/61106155…

分布式训练原理总结(DP、PP、TP 、ZeRO)

文章目录 一、分布式训练基础知识1.1 集合通信、集合通信库1.2 通信模式1.2.1 Parameter Server&#xff08;2014&#xff09;1.2.2 Ring-AllReduce&#xff08;2017&#xff09; 1.3 同步范式1.4 大模型训练的目标公式 二、数据并行2.1 DataParallel&#xff08;DP)2.2 Distri…

c++学习3——几个感悟

一些感悟 1 虚拟目录2 浏览器和微信的本质区别3 资源文件 1 虚拟目录 电脑文件中并没有这个目录&#xff0c;比如vs2019在编程时&#xff0c; c的头文件.h文件和源文件.cpp文件实际上在一个目录&#xff0c;但是在vs2019中前者显示在头文件文件夹中&#xff0c;后者显示在源文…

mybatis-plus技巧--动态表名-多语句-拼接sql--关于mybatis的mysql分页查询总数的优化思考

文章目录 动态表名xml表名填充表名拦截器每天按统计每次设置 多语句操作forEach动态拼接 参数构建java进行拼接sqlmysql分页查询总数count不要使用count&#xff08;常数&#xff09;&#xff0c;count&#xff08;列名&#xff09;代替count(*)自己计数 SQL_CALC_FOUND_ROWSxm…

左偏树学习笔记

定义 堆&#xff0c;是一棵树&#xff0c;且每个节点的键值都大于等于 / 小于其父亲的键值。 左偏树是一种可合并的堆&#xff0c;可以以 O ( log ⁡ n ) O(\log n) O(logn) 的复杂度实现合并。 性质 左偏树满足堆的性质。 我们设定一个值 dist \text{dist} dist&#xf…