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

一.算法效率

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;
}

    

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

区块链论文总结速读--CCF B会议 ICDCS 2023 共8篇

Conference&#xff1a;IEEE 43rd International Conference on Distributed Computing Systems (ICDCS) CCF level&#xff1a;CCF B Categories&#xff1a;Computer Architecture/Parallel and Distributed Computing/Storage Systems 计算机体系结构/并行与分布计算/存储…

如何用OceanBase的 Load Data 导入CSV文件

0 前言 CSV文件&#xff08;Comma-Separated Values&#xff0c;字符分隔值&#xff09;是一种普遍采用的数据存储格式&#xff0c;有不少企业和机构都用它来进行数据的管理和存储。身为开发者&#xff0c;您可能经常遇到这样的需求&#xff1a;需要将CSV的数据导入OceanBase数…

3-2 STM32c8t6实现流水灯

实物接线如下&#xff1a; 软件代码 #include "stm32f10x.h" // Device header #include "delay.h" int main(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_Init…

盘点:国内物流装备商的出海策略和战果

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 随着物流行业的快速发展和全球市场的不断开放&#xff0c;越来越多的物流装备企业开始将目光投向海外市场&#xf…

安卓中级控件(图形、选择按钮、文本输入、对话框)

图形定制 图形Drawable Android把所有能够显示的图形都抽象为Drawable类&#xff08;可绘制的&#xff09;。这里的图形不止是图片&#xff0c;还包括色块、画板、背景等。 包含图片在内的图形文件放在res目录的各个drawable目录下&#xff0c;其中drawable目录一般保存描述性…

spring-boot示例

spring-boot版本&#xff1a;2.0.3.RELEASE 数据库: H2数据库 &#xff08;嵌入式内存性数据库&#xff0c;安装简单&#xff0c;方便用于开发、测试&#xff0c;不适合用于生产&#xff09; mybatis-plus框架&#xff0c;非常迅速开发CRUD

【LAMMPS学习】八、基础知识(5.3)Body particles体粒子

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑&#xff0c;而没有考虑到具体的市场需求&#xff0c;使得该模型结构复杂&#xff0c;部分功能冗余&#xff0c;因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求&#xff0c;实现起来也比较…

java:错误:不支持发行版本

你在运行的时候是否遇见过这样的问题: 有时候新建一个Java项目后&#xff0c;运行起来就会提示这样的错误。主要原因是因为项目使用的Java版本和安装的Java版本不符合 &#xff0c;在这里总结一下解决方法: 首先点击file的project 把Java编译器也设置成 一样的版本 即可解决问…

计算机毕业设计python_django宠物领养系统z6rfy

本宠物领养系统主要包括两大功能模块&#xff0c;即管理员模块、用户模块。下面将对这两个大功能进行具体功能需求分析。 &#xff08;1&#xff09;管理员&#xff1a;管理员登录后主要功能包括个人中心、用户管理、送养宠物管理、地区类型管理、失信黑名单管理、申请领养管理…

c#数据库: 4.修改学生成绩

将4年级的学生成绩全部修改为100分,。修改前的学生信息表如图所示: using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks;namespace StudentUpdate {internal class Program{s…

麒麟服务器操作系统SP3如何设置GRUB密码

原文链接&#xff1a;麒麟服务器操作系统SP3如何设置GRUB密码 Hello&#xff0c;大家好啊&#xff01;为了增强系统的安全性&#xff0c;设置GRUB&#xff08;GNU GRand Unified Bootloader&#xff09;密码是一个非常有效的方法。这可以防止未经授权的用户修改启动参数或使用恢…