算法效率的判断及一些典型例题的讲解

一.算法效率

1.用处:判断算法的好坏,好的算法应该是高效的

2算法效率取决于时间复杂度和空间复杂度

<1>时间复杂度

    1.1概念:算法中基本操作的执行次数就是算法的时间复杂度

    1.2表示:大O的渐进表示法,例如O(N)

    1.3计算:以最坏运行情况算出可能需要执行的最多操作数的表达式,只保留最高阶项,并舍弃                      其系数

    1.4例子说明

    1.5常见的时间复杂度

O(1)常数阶
O(N)线性阶
O(N^2)平方阶
O(logN)对数阶例如:二分查找的空间复杂度为O(logN)
O(nlogn)nlogn阶
O(2^n)指数阶

例如:使用递归法计算斐波那契数,时间复杂度为O(2^n)

当时间复杂度为指数阶时,说明该方法不适用与解题,效率太低

<2>空间复杂度

     2.1概念:是对运行过程中额外开辟空间大小的度量

     2.2表示:大O的渐进表示法,例如O(1)

     2.3计算:数在实现程序的过程中共额外开辟了多少个变量,保留最高阶项,并舍弃其系数

     2.4例子说明:

     2.5常见的空间复杂度:

O(1)开辟有限的变量
O(N)新开辟了一个数组
O(N^2)

二.典型例题

1.旋转数组

  1.1题目介绍:给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

. - 力扣(LeetCode)

  1.2解法

  <1>逐个旋转

        1.1思路讲解:将尾部的数据拿下来,再将其他元素向后挪一位,最后将拿下来的数据放在头                                 部,重复操作,直至完成轮转(注意:当传入的k大于数组大小时会进行一些轮                                 回,可以先将k%数组大小,保证k<数组大小,提高效率;在进行数组往后操                                   作时需要从后往前操作)

        1.2时间复杂度:O(N^2)     空间复杂度:O(1)

        1.3代码实现

void rotate(int* nums, int numsSize, int k) {
    k%=numsSize;//避免重复操作
    int tmp=0;
    while(k--)
    {
        tmp=nums[numsSize-1];
        for(int i=numsSize-1;i>0;i--)
        {
            nums[i]=nums[i-1];
        }
        nums[0]=tmp;
    }
}

 <2>分三段逆置

        2.1思路讲解:封装一个函数用于将数组逆置,在进行轮转的位置将原数组视为两部分分别逆                                 置,最后将整个数组逆置即可(注意当传入的k大于数组大小时会进行一些轮                                     回,可以先将k%数组大小,保证k<数组大小,提高效率)

        2.2时间复杂度:O(N)     空间复杂度:O(1)

        2.3代码实现

//数组逆置
void reverse(int* nums,int left,int right)
{
    int tmp=0;
    while(left<right)
    {
        tmp=nums[left];
        nums[left]=nums[right];
        nums[right]=tmp;
        left++;
        right--;
    }
}

void rotate(int* nums, int numsSize, int k) {
    k%=numsSize;//避免重复操作
    reverse(nums,0,numsSize-k-1);
    reverse(nums,numsSize-k,numsSize-1);
    reverse(nums,0,numsSize-1);
}

<3>创建一个新数组

        3.1思路讲解:创建一个新数组,先按要轮转的位置将数据先后拷贝至新数组中,最后将新数                                 组的元素拷贝回原数组

        3.2时间复杂度:O(N)     空间复杂度:O(N)

        3.3代码实现

void rotate(int* nums, int numsSize, int k) {
    k%=numsSize;//避免重复操作
    int arr[]={0};
    int i=0;
    for(i=numsSize-k,j=0;i<numsSize;i++,j++)
    {
        arr[j]=nums[i];
    }
    for(i=0;i<numsSize-k;i++,j++)
    {
        arr[r]=nums[i];
    }
    for(i=0;i<numsSize;i++)
    {
        nums[i]=arr[i];
    }
}

2.找两个链表是否有公共节点,若有返回第一个公共节点的地址

2.1题目介绍:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始                         节点。如果两个链表不存在相交节点,返回 null 。

. - 力扣(LeetCode)

2.2解法

<1>思路:1.判断是否两链表相交:看他们的尾结点的地址是否相同,若相同则相交

                 2.找出较长的链表与较短链表的差值,让长链表先走差值步,再让两链表同时走,当他                      们指向的空间相同时,即是第一个公共节点处

<2>时间复杂度:O(N)       空间复杂度:O(1)

<3>代码实现

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    //判断是否有公共节点
    ListNode* A=headA;
    ListNode* B=headB;
    int len1=0;
    int len2=0;
    while(A)
    {
        A=A->next;
        len1++;
    }
    while(B)
    {
        B=B->next;
        len2++;
    }
    if(A!=B)
    {
        return NULL;
    }
    else
    {
        int gap=abs(len1-len2);
        ListNode* greatlist=headA;
        ListNode* shortlist=headB;
        if(len1<len2)
        {
            greatlist=headB;
            shortlist=headA;
        }
        //先让长链表走直至弥补两链表的差距
        while(gap--)
        {
            greatlist=greatlist->next;
        }
        while(greatlist && shortlist)
        {
            if(greatlist==shortlist && greatlist->val==shortlist->val)
            {
                return greatlist;
            }
            greatlist=greatlist->next;
            shortlist=shortlist->next;
        }
        return NULL;
    }

    
}

3.判断链表是否带环

<1>题目介绍:给你一个链表的头节点 head ,判断链表中是否有环。

. - 力扣(LeetCode)

<2>思路:定义slow,fast两个指针,slow走一步,fast走两步,若在某时刻slow=fast,则说明链表                中带环

<3>方法证明

<4>代码实现

typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    ListNode* fast=head;
    ListNode* slow=head;
    while(fast!=NULL)
    {
        slow=slow->next;
        if(fast->next==NULL)
        {
            return false;
        }
        else
        {
            fast=fast->next->next;
        }
        if(slow==fast)
        {
            return true;
        }
    }
    return false;

    
}

<5>拓展:Q:当fast=3*slow时,可以用来判断是否带环吗?

                 A:可以

                 Q:当fast=4*slow呢?

                 A:可参考上述分析,这里就不在一一证明了

4.返回带环链表进入环时的第一个节点地址

<1>题目介绍:给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

. - 力扣(LeetCode)

<2>思路:先判断是否为带环链表,记录slow和fast相遇时的位置,让cur指向头节点,meet位相                    遇的位置,让meet和cur同时开始走,当meet和cur相等时,cur刚好位于入环的第一个                    节点处

<3>方法证明:

<4>代码实现:

typedef struct ListNode ListNode;
ListNode* hasCycle(ListNode *head) {
    ListNode* fast=head;
    ListNode* slow=head;
    while(fast!=NULL)
    {
        slow=slow->next;
        if(fast->next==NULL)
        {
            return NULL;
        }
        else
        {
            fast=fast->next->next;
        }
        if(slow==fast)
        {
            return slow;
        }
    }
    return NULL;
}

struct ListNode *detectCycle(struct ListNode *head) {
    ListNode* cur=head;
    ListNode* meet=hasCycle(head);
    if(meet==NULL)
    {
        return NULL;
    }
    else
    {
        while(cur)
        {
            if(cur==meet)
            {
                return cur;
            }
            cur=cur->next;
            meet=meet->next;
        }
        return NULL;
    }
}

5.随机链表的复制

<1>题目介绍:

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。

. - 力扣(LeetCode)

<2>思路:先开辟新节点,将其连在原链表的每个节点后面,再对新节点的random进行赋值,最后将原链表与拷贝链表分离

<3>代码实现:

typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)
    {
        return NULL;
    }
    Node* cur=head;
    //遍历原链表,复制其内容并插在原节点的后面
    while(cur)
    {
        Node* copy=(Node*)malloc(sizeof(Node));
        copy->val=cur->val;
        copy->next=cur->next;
        copy->random=NULL;
        cur->next=copy;
        cur=copy->next;
    }
    //再遍历链表,设置随机指针
    cur=head;
    while(cur)
    {
        Node* copy=cur->next;
        if(cur->random)
        {
            copy->random=cur->random->next;
        }
        cur=copy->next;
    }

    //将复制的链表和原链表分隔开
    Node* newhead=NULL,*prev,*next;
    cur=head;
    while(cur)
    {
        next=cur->next->next;
        if(newhead==NULL)
        {
            newhead=cur->next;
            prev=cur->next;
        }
        else
        {
            prev->next=cur->next;
            prev=cur->next;
        }
        cur->next=next;
        cur=next;
    }
    return newhead;
}

    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java技术栈快速复习02_前端基础知识总结

前端基础 经典三件套&#xff1a; html&#xff08;盒子&#xff09;css&#xff08;样式&#xff09;JavaScript&#xff08;js&#xff1a;让盒子动起来&#xff09; html & css HTML全称&#xff1a;Hyper Text Markup Language(超文本标记语言)&#xff0c;不是编程语…

记一次生产事故的排查和解决

一. 事故概述 春节期间, 生产系统多次出现假死不可用现象, 导致绝大部分业务无法进行. 主要表现现象为接口无法访问. 背景为900W客户表和近实时ES, 以及春节期间疫情导致的普通卖菜场景近似秒杀等. 二. 排查过程 优先排查了info, error, catalina日志, 发现以下异常: 主要的…

边循环边删除List中的数据

List边循环&#xff0c;边删除&#xff1b;这种一听感觉就像是会出问题一样&#xff0c;其实只要是删除特定数据&#xff0c;就不会出问题&#xff0c;你如果直接循环删除所有数据&#xff0c;那可能就会出问题了&#xff0c;比如&#xff1a; public static void main(String[…

公考学习平台|基于SprinBoot+vue的公考学习平台(源码+数据库+文档)

公考学习平台目录 目录 基于SprinBootvue的公考学习平台 一、前言 二、系统设计 三、系统功能设计 5.1用户信息管理 5.2 视频信息管理 5.3公告信息管理 5.1论坛信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

React的useEffect

概念&#xff1a;useEffect是一个React Hook函数&#xff0c;组件渲染之后执行的函数 参数1是一个函数&#xff0c;可以把它叫做副作用函数&#xff0c;在函数内部可以放置要执行的操作参数2是一个数组&#xff08;可选参&#xff09;&#xff0c;在数组里放置依赖项&#x…

Liunx发布tomcat项目

Liunx在Tomcat发布JavaWeb项目 1.问题2.下载JDK3.下载Tomcat4.Tomcat本地JavaWeb项目打war包、解压、发布5.重启Tomcat,查看项目 1.问题 1.JDK 与 Tomcat 版本需匹配&#xff0c;否则页面不能正确显示 报错相关&#xff1a;Caused by: java.lang.ClassNotFoundException: java…

十一、大模型-Semantic Kernel与 LangChain 的对比

Semantic Kernel 与 LangChain 的对比 Semantic Kernel 和 LangChain 都是用于开发基于大型语言模型&#xff08;LLM&#xff09;的应用程序的框架&#xff0c;但它们各有特点和优势。 基本概念和目标 Semantic Kernel 是一个由微软开发的轻量级 SDK&#xff0c;旨在帮助开发…

每日OJ题_DFS爆搜深搜回溯剪枝⑤_力扣37. 解数独

目录 力扣37. 解数独 解析代码 力扣37. 解数独 37. 解数独 难度 困难 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的…

C++--const成员及const取地址操作符重载

前言 今天我们来了解一下const成员的基本使用,以及const取地址重载的运用 来开始今天的学习 const成员 1.基本定义, 将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数 隐含的*this指针&#xff0c;表明在该成员函…

Android4.4真机移植过程笔记(二)

5、盘符挂载 先定义overlay机制路径&#xff0c;后面storage_list.xml要用到&#xff1a; 在路径&#xff1a; rk3188_android4.4.1/device/rockchip/OK1000/overlay/frameworks/base/core/res/res/xml/定义好&#xff0c;注意名字要和emmc的代码片段&#xff08;往下面看&am…

python学习笔记----安装pycharm(1)

一、安装pycharm 1. 下载并安装pycharm https://www.jetbrains.com/pycharm/download2.汉化pycharm 安装插件并重启IDE完成汉化 二、 第一个python程序

Flask教程1:flask框架基础入门,路由、模板、装饰器

文章目录 一、 简介二、 概要 一、 简介 Flask是一个非常小的Python Web框架&#xff0c;被称为微型框架&#xff1b;只提供了一个稳健的核心&#xff0c;其他功能全部是通过扩展实现的&#xff1b;意思就是我们可以根据项目的需要量身定制&#xff0c;也意味着我们需要学习各…

分享天某云对象存储开发的体验

最近体验了天某云对象存储的功能&#xff0c;作为一名资深开发者&#xff0c;开发体验差强人意&#xff0c;与阿里云存在一定的差距。 首先在开发文档上居然没有基于nodejs的代码示例&#xff0c;只有java,c#,go等的代码示例&#xff0c;虽然有javascript的&#xff0c;但那也只…

Outlook大附件插件 有效解决附件大小限制问题

很多企业都是使用Outlook来进行邮件的收发&#xff0c;可是由于附件大小有限&#xff0c;导致很多大文件发不出去&#xff0c;就会产生Outlook大附件插件这种业务需求。 邮件系统在发送大文件时面临的限制问题主要如下&#xff1a; 1、附件大小限制&#xff1a;大多数邮件服务…

net lambda 、 匿名函数 以及集合(实现IEnumerable的 如数组 、list等)

匿名函数&#xff1a;》》》 Action a1 delegate(int i) { Console.WriteLine(i); }; Lambda:>>> Aciont a1 (int i) > { Console.WriteLine(i); }; 可以简写 &#xff08;编译器会自动根据委托类型 推断&#xff09; Action a1 &#xff08;i&#xff09;> {…

前端vite+rollup前端监控初始化——封装基础fmp消耗时间的npm包并且发布npm beta版本

文章目录 ⭐前言&#x1f496;vue3系列文章 ⭐初始化npm项目&#x1f496;type为module&#x1f496;rollup.config.js ⭐封装fmp耗时计算的class&#x1f496;npm build打包class对象 ⭐发布npm的beta版本&#x1f496; npm发布beta版本 ⭐安装web-performance-tool的beta版本…

springcloud自定义全局异常

自行创建一个实体类 /*** 全局异常处理类**/ ControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class) ResponseBody public Result error(Exception e){e.printStackTrace(); return Result.fail();}/*** 自定义异常处理方法* param e * re…

GPU 架构与 CUDA 关系 并行计算平台和编程模型 CUDA 线程层次结构 GPU 的算力是如何计算的 算力峰值

GPU 架构与 CUDA 关系 本文主要包含 NVIDIA GPU 硬件的基础概念、CUDA(Compute Unified Device Architecture)并行计算平台和编程模型,详细讲解 CUDA 线程层次结构,最后将讲解 GPU 的算力是如何计算的,这将有助于计算大模型的算力峰值和算力利用率。 GPU 硬件基础概念GP…

GB32960解析工具

几年前搞了一个用Qt开发的国标32960报文解析工具。分享给大家&#xff0c;只用1积分便可以下载。 国标32960新能源车协议解析工具资源-CSDN文库

数据结构—C语言实现双向链表

目录 1.双向带头循环链表 2.自定义头文件&#xff1a; 3.List.cpp 文件 3.1 newnode()函数讲解 3.2 init() 函数 初始化 3.3 pushback()函数 尾插 3.4 pushfront()函数 头插 3.5 popback() 尾删 3.6 popfront() 函数 头删 3.7 insert()函数 在pos之后插入 3.8 popbac…