空间复杂度与链表刷题

"一切的一切都是你自己在感应."

本文索引

  • 空间复杂度
    • 复杂度实例
      • 实例1
      • 实例2
      • 实例3
  • 链表题目
    • 1. 返回倒数第K个节点
    • 2. 链表的回文结构
    • 3. 相交链表
    • 4. 随机链表的复制
    • 5. 环形链表
  • 总结:

前言:
本文主要探究空间复杂度与链表题目讲解
更多文章点击主页: 酷酷学!!!
如果此文对您有帮助, 您的点赞与关注是我最大的动力 !


正文开始

空间复杂度

空间复杂度也是一个数学表达式, 是对一个算法在运行时临时占用存储空间大小的量度.
空间复杂度不是程序占用了多少bytes的空间, 因为这个也没太大意义, 所以空间复杂度算的是变量的个数. 空间复杂度计算规则基本跟时间复杂度类似, 也使用大O渐进表示法.
注意: 函数运行时所需要的栈空间(存储参数,局部变量,一些寄存器信息等)在编译期间已经确定好了, 因此空间复杂度主要通过函数在运行时候显示申请的额外空间来确定.

复杂度实例

实例1

// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{assert(a);for (size_t end = n; end > 0; --end){int exchange = 0;for (size_t i = 1; i < end; ++i){if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0)break;}
}

解析:

首先解决这个问题我们需要计算额外的空间, 这里一共创建了三个变量, end, exchange, i ,使用了常数个额外空间,所以空间复杂度为 O(1)

实例2

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{if (n == 0)return NULL;long long* fibArray = (long long*)malloc((n + 1) * sizeof(long long));fibArray[0] = 0;fibArray[1] = 1;for (int i = 2; i <= n; ++i){fibArray[i] = fibArray[i - 1] + fibArray[i - 2];}return fibArray;
}

解析:
在这里插入图片描述
这里,一共开辟了N个函数栈帧, 动态开辟了N个空间,空间复杂度为 O(N),而时间复杂度为O(2^N).

实例3

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{if (N == 0)return 1;return Fac(N - 1) * N;
}

解析:

在这里插入图片描述

递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)

链表题目

1. 返回倒数第K个节点

题目链接: 返回倒数第K个节点

题目描述:

在这里插入图片描述
题目分析:
       本题的解法有很多种, 例如创建数组, 或者将链表反转等等, 这里我们采用一种比较经典的双指针法, 只需要变量一遍链表, 并且空间复杂度为O(1),时间复杂度为O(N), 首先采用数理思想, 定义快慢指针, 快指针先走K个节点,然后在同时走, 因为中间的差距一直为K,所以当快指针走到NULL的时候, 此时慢指针即为倒数第K个节点.因为题目要求K值是有效的, 所以我们也无需判断K值是否有效.

画图演示:

在这里插入图片描述

代码如下:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*///时间复杂度为O(1)
int kthToLast(struct ListNode* head, int k){struct ListNode* fast = head;struct ListNode* slow = head;while(k--){fast = fast->next;}while(fast){fast = fast->next;slow = slow->next;}return slow->val;
}

2. 链表的回文结构

题目链接: 链表的回文结构

题目描述:

在这里插入图片描述
题目分析:

       本题可以说是一个综合题, 结合前面对链表的掌握, 理解了思路就变得比较简单, 首先回文结构并不陌生, 数组题目中我们已经见过, 例如12321, 或者1221就是回文结构, 如果是数组, 我们可以采用双指针法, 一个在头, 一个在尾, 两两比较, 分别向中间前进, 但是此时是个链表, 该如何比较呢.

       单链表链表的结构不能直接从后向前遍历, 首先第一步, 寻找中间节点, 然后将中间节点之后的链表进行反转, 然后从头结点开始与中间节点之后的链表的值进行比较, 当然我们需要讨论链表为奇数或者偶数的情况, 但是不难发现, 如下图所示, 不管是奇数还是偶数, 都不影响, 我们只需要判断其中一个链表是否走到NULL.

画图演示:

在这里插入图片描述

代码如下:

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
#include <cstddef>
class PalindromeList {
public://1. 寻找中间节点struct ListNode * midNode(ListNode* A){struct ListNode * fast = A;struct ListNode * slow = A;while(fast&&fast->next){fast = fast->next->next;slow = slow->next;}return slow;}//2.反转后半段链表struct ListNode *reverseNode(ListNode* mid){if(mid == NULL){return mid;}struct ListNode * l1 = NULL;struct ListNode * l2 = mid;struct ListNode * l3 = mid->next;while(l2){l2->next = l1;l1 = l2;l2 = l3;if(l3){l3 = l3->next;}}return l1;}bool chkPalindrome(ListNode* A) {struct ListNode * mid = midNode(A);struct ListNode * B = reverseNode(mid);while(A&&B){if(A->val != B->val){return false;}A = A->next;B = B->next;}return true;// write code here}
};

3. 相交链表

题目链接: 相交链表

题目描述:

在这里插入图片描述

题目分析:

       判断链表相交, 如果说一个一个比较的话, 链表A的节点依次和链表B的节点一次进行比较这样太麻烦了, 而且时间复杂度为O(N^2), 那么, 判断链表相交 ,我们可以遍历链表, 如果两个链表最后一个节点相等的话, 那么就一定相交, 但是如何返回第一个相交节点呢, 通过分别比较吗, 大可不必, 在我们遍历链表的时候, 我们可以顺便计算出链表的相对差值, 然后让长的链表走差值的距离, 在同时走, 那么只要两个节点相遇, 就是第一个相交节点.

画图演示:

在这里插入图片描述

代码如下:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* cur1 = headA;struct ListNode* cur2 = headB;int long1 = 0,long2 = 0;while(cur1->next){long1++;cur1 = cur1->next;}while(cur2->next){long2++;cur2 = cur2->next;}if(cur1 != cur2){return NULL;}struct ListNode* LongList = headA;struct ListNode* ShortList = headB;if(long2>long1){LongList = headB;ShortList = headA;}int dig = abs(long1-long2);while(dig--){LongList = LongList->next;}while(LongList!=ShortList){LongList = LongList->next;ShortList = ShortList ->next;}return LongList;
}

4. 随机链表的复制

在这里插入图片描述
在这里插入图片描述
题目分析:
       深拷贝就是复制出来一个一模一样的链表, 如果我们直接创建一个新的节点, 但是对random的处理比较麻烦, 我们需要计算出相对位置, 以确保random的指向正确. 这里我们换一种思路, 如下图所示, 我们在每个节点之后插入一个新的节点, 此时处理random就比较简单了,拷贝节点的 random的指向就是cur->random->next. 最后再将拷贝节点拿下来尾插, 成为一个新的链表.虽然破坏了原链表的结构, 我们也可以进行恢复, 但是题目没有要求 ,所以, 我们也可以不用恢复.

画图演示:

在这里插入图片描述

代码如下:

/*** Definition for a Node.* struct Node {*     int val;*     struct Node *next;*     struct Node *random;* };*/struct Node* copyRandomList(struct Node* head) {struct Node* cur = head;while(cur){struct Node* copyNode = (struct Node*)malloc(sizeof(struct Node));copyNode->val = cur->val;copyNode->next = cur->next;cur->next = copyNode;cur = copyNode->next;}cur = head;while(cur){   struct Node* copy = cur->next;if(cur->random == NULL){copy->random = NULL;}else{copy->random = cur->random->next;}cur = copy->next;}cur = head;struct Node* copyHead = NULL;struct Node* copyTail = NULL;while(cur){struct Node* copy = cur->next;//Node* next = copy->next;if(copyTail == NULL){copyHead = copyTail = copy;}else{copyTail->next = copy;copyTail = copyTail->next;}cur = copy->next;//cur = next;恢复原链表}return copyHead;
}

5. 环形链表

题目链接:环形链表2

题目描述:

在这里插入图片描述

代码如下:

这里我们采用双指针法, 快指针一次走两步 , 慢指针一次走一步, 因为有相对速度, 所以当慢指针进入环时,快指针开始追击, 当快指针追击上满指针则带环, 若追击不上,则不带环.
面试时可能会问到:

  1. 为什么一定会相遇,有没有可能会错过, 永远追不上? 请证明
  2. slow一次走一步, fast走3步 4步 5步 一定能追上吗? 请证明

首先证明问题1, 一次走一步, 假设slow进环时, fast和slow的距离是N, 那么fast追击slow过程中变化距离如下, 每次追击一次, 距离就缩小1, 距离为0就追上了.
在这里插入图片描述

证明问题2:

这里我们假设fast一次走3步, 当slow进环时, fast开始追击, 每次的距离变化如下, 如果N是偶数的情况下,那么就一定可以追上, 当为奇数时,就进入到第二次的追击, 假设环的长度为C, 那么下一次追击的距离就为C-1, 那如果C-1为偶数的话那么就可以追上, 但是如果C-1又为奇数那么就永远追不上, 此时我们就需要证明会不会永远追不上, 也就是证明当N为奇数的情况下, C-1为奇数, 即C为偶数吗, 通过fast走的距离和slow走的距离, 我们可以知道3slow = fast .

fast走的距离为:L + xC +C-N, (L为未进环时的长度, C为环的长度, x为走的圈数, N为slow进环时和fast的距离)
slow走的距离为: L
由此可得3L = L+X
C+C-N
化简可以得到, 2L = (X+1)C - N
此时只需证明N为奇数, C能否为偶数, 是偶数就永远追不上
根据等式 2L一定为偶数, 而N假设为奇数, 那么C如果为偶数的话,
即 偶数 = (X+1)*偶数 - 奇数 等式不成立,
因为只有奇数-奇数才能等于偶数, 所以C 一定为奇数,故不可能追不上
其余证明思想类似

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

接下来, 我们判断出了是带环链表, 那我们如何找到入环时的第一个节点呢?

先来分析一波
假设相遇的时的节点为meet, 那么slow走的路程为L+N, fast走的路程为L+X * C +N ,根据2slow = fast,我们又可以得到
2(L+N) = L+X*C + N
化简得到
L+N = X *C
L = X *C-N
L = (X-1)C +C -N
(X-1)C可以想象成走了多少圈但是还是会回到meet那个位置, 所以L的到第一个入环节点的距离等于C-N
那么我们只需要随便找两个指针, 一个从head开始走, 一个从meet开始走, 只要他们两个相遇, 那么就是第一个入环节点.

在这里插入图片描述
在这里插入图片描述

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* fast = head;struct ListNode* slow = head;while(fast&&fast->next){fast = fast->next->next;slow = slow->next;if(fast==slow){struct ListNode* meet = slow;fast = head;while(meet!=fast){meet = meet->next;fast = fast->next;}return meet;}}return NULL;
}

总结:

空间复杂度表示算法在运行过程中需要使用的额外的空间资源。空间复杂度的计算通常是以算法需要的额外空间大小来衡量的。链表是一种常见的数据结构,用于存储和操作一系列具有关联关系的数据元素。
链表的面试题常见的有:
反转链表: 将一个链表反转,即将链表中的节点逆序排列。
链表中倒数第k个节点: 找到链表中倒数第k个节点的值。
链表是否有环: 判断一个链表是否存在环。
合并两个有序链表: 将两个有序链表合并为一个有序链表。
删除链表中的重复元素: 删除链表中重复的元素,使得每个元素只出现一次。
在解决链表面试题时,常用的方法有:
递归法: 使用递归的方式处理链表的问题,递归可以简化问题的处理过程。
快慢指针法: 使用快慢指针来寻找链表中的某个位置,如链表中的中间节点、倒数第k个节点等。
翻转链表法: 使用指针来改变链表节点的指向,实现链表的翻转。
在面试过程中,对于链表问题,需要注意空指针的处理,以及边界条件的判断。同时,对于链表的基本操作,如插入、删除等,也要熟练掌握。

最后感谢关注点赞, 如果错误欢迎指正.

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

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

相关文章

探索白啤:清爽与纯净的完善呈现

啤酒的世界色彩斑斓&#xff0c;各种风格迥异的啤酒满足着人们不同的口味需求。而在众多啤酒中&#xff0c;白啤以其与众不同的清爽与纯净口感&#xff0c;成为了许多人的心头好。Fendi club白啤作为精酿啤酒的代表&#xff0c;更是将这种口感发挥到了超卓。 Fendi club白啤的酿…

撤销及变更:31个自然基金项目!

本周投稿推荐 SSCI • 2区社科类&#xff0c;3.0-4.0&#xff08;社科均可&#xff09; EI • 计算机工程类&#xff08;接收广&#xff0c;录用极快&#xff09; SCI&EI • 4区生物医学类&#xff0c;1.5-2.0&#xff08;录用率99%&#xff09; • 1区工程类&#…

命名规范总结Java

小驼峰命名 主要用于变量和方法的命名&#xff0c;当标识符是一个单词时首字母小写&#xff0c;当标识符为多个单词时第一个单词首字母小写&#xff0c;其他单词首字母大写 大驼峰命名 主要用于类(Class)名等。标识符各个单词首字母大写。 全部大写命名 常量名 全部小写命…

凡尔码安全巡检卡替代传统纸质记录卡

建筑行业、物业管理、医院等行业的安全巡检的记录方式通常以&#xff1a;1、纸质记录&#xff1a;巡检人员使用纸质巡检表格&#xff0c;手动填写巡检时间、巡检区域、巡检发现的问题以及处理情况。这种方式简单直接&#xff0c;但可能存在信息记录不完整、易丢失等问题。 2、电…

uniapp音乐播放整理

一、前置知识点 1.1 音频组件控制-uni.createInnerAudioContext() 创建并返回内部 audio 上下文 innerAudioContext 对象。 主要用于当前音乐播放&#xff1b; 1.1.1 innerAudioContext属性 属性类型说明只读平台差异说明srcString音频的数据链接&#xff0c;用于直接播放…

聚观早报 | 乐道L60实车曝光;《萤火突击》公测定档

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月11日消息 乐道L60实车曝光 《萤火突击》公测定档 华为官网更新管理层信息 OPPO Reno12 Pro细节曝光 三星电子…

瀚高数据库(HighGoDB)Windows安装使用

1.下载 2.安装 瀚高数据库下载与安装&#xff08;Windows版&#xff09;-CSDN博客 3.连接工具 4.建库、建表操作 瀚高数据库管理工具-CSDN博客 *报错Cant access non-default database&#xff0c;需要右键数据库-设为活动对象 5.导入外部数据&#xff08;迁移、对比&…

Stable Diffusion写真完整教程

前言 最近自己对AI非常痴迷&#xff0c;并且今后也会一直在这个领域深耕&#xff0c;所以就想着先入门&#xff0c;因此花时间研究了一番&#xff0c;还好&#xff0c;出了点小成果&#xff0c;接下来给大家汇报一下。 AI绘画 提到AI绘画&#xff0c;大家可能立马会想到made…

住宅IP代理和数据中心/机房IP代理之间的区别

一、什么是数据中心/机房IP代理&#xff1f; 数据中心/机房IP代理是使用数据中心拥有并进行分配和管理的IP的代理&#xff0c;俗称机房IP代理。 二、数据中心/机房IP代理的特点 与住宅代理通过使用ISP拥有和分配的IP地址的设备路由请求的情况不同&#xff0c;数据中心代理利…

品鉴中的挑战与探索:如何勇敢尝试不同类型的云仓酒庄雷盛红酒

品鉴云仓酒庄雷盛红酒不仅是一种感官的享受&#xff0c;更是一种挑战与探索的过程。不同类型的云仓酒庄雷盛红酒具有各自与众不同的风味和特点&#xff0c;通过勇敢尝试不同类型的红酒&#xff0c;我们可以拓展自己的品鉴视野&#xff0c;发现更多未知的美妙滋味。 首先&#x…

postgresql中写python去读取HDFS数据,像表一样使用。

简介 首先postgresql是支持python的&#xff0c;在安装postgresql数据库的时候需要执行python支持。可以使用python进行写fundcation 自然也就可以自定义funcation去读取HDFS文件&#xff0c;以此替换掉hive的&#xff0c;省去中间频繁切换服务器的麻烦。 安装postgresql use…

SpringBoot+Vue实现图片滑块和文字点击验证码

一、背景 1.1 概述 传统字符型验证码展示-填写字符-比对答案的流程&#xff0c;目前已可被机器暴力破解&#xff0c;应用程序容易被自动化脚本和机器人攻击。 摒弃传统字符型验证码&#xff0c;采用行为验证码采用嵌入式集成方式&#xff0c;接入方便&#xff0c;安全&#…

【Android】Kotlin学习之Kotlin方法的声明和传参

方法声明 普通类的方法 静态类的方法 不需要构建实例对象, 可以通过类名直接访问静态方法 : NumUtil.double(1) companion object 伴生类的方法 使用companion object 在普通类里定义静态方法 参数 括号内传入方法 : 当参数是方法时, 并且是最后一个参数 , 可以使用括号外…

有什么实用的还原试卷的app免费?6个软件教你快速进行还原试卷

有什么实用的还原试卷的app免费&#xff1f;6个软件教你快速进行还原试卷 在现代化的教学环境中&#xff0c;使用数字化工具进行试卷还原变得愈发重要。以下是六个实用的、免费的应用程序&#xff0c;它们为还原试卷提供了便捷的解决方案。 FunAI&#xff1a; 这款应用程序可…

【JVM】ASM开发

认识ASM ASM是一个Java字节码操纵框架&#xff0c;它能被用来动态生成类或者增强既有类的功能。 ASM可以直接产生二进制class文件&#xff0c;也可以在类被加载入虚拟机之前动态改变类行为&#xff0c;ASM从类文件中读入信息后能够改变类行为&#xff0c;分析类信息&#xff…

中仕公考:怎么看岗位是否有编制?

1、看公告标题 有编&#xff1a;公告标题中含有编内、xx地区事业单位招聘、xx教育系统招聘……等关键词&#xff0c;这样的公告是有编制的。 无编&#xff1a;公告标题含有编外、非在编、临聘、劳务派遣、政府购买岗位……等关键词&#xff0c;说明是没有编制的 2、看公告引导…

算法基础01一快速排序,归并排序,二分

一.排序 1.快速 排序 基于分治 确定分界点 左 右 中间 随机划分区间 左半边<x >x在右半边递归处理左右两端 #include<iostream>using namespace std;const int N 1e6 10;int n; int q[N]; void quick_sort(int q[],int l,int r) {if(l>r)return;//边界&…

表格内容高效拆分,自定义行数随心所欲,让数据处理更高效!

在信息化社会的今天&#xff0c;表格成为了我们处理数据、整理信息的重要工具。然而&#xff0c;当表格内容过于庞大时&#xff0c;如何高效地拆分表格内容成为了摆在我们面前的一大难题。传统的拆分方法往往耗时耗力&#xff0c;且难以满足我们个性化的需求。 首先&#xff0…

【JAVA进阶篇教学】第十三篇:Java中volatile关键字讲解

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第十三篇&#xff1a;volatile关键字讲解。 在 Java 中&#xff0c;volatile关键字是一种轻量级的同步机制&#xff0c;用于确保变量的可见性和禁止指令重排序。本文将详细解释volatile关键字的工作原理、可见性保证以及…

Goland GC

Goland GC 引用Go 1.3 mark and sweep 标记法Go 1.5 三色标记法屏障机制插入屏障删除写屏障总结 Go 1.8 混合写屏障(hybrid write barrier)机制总结 引用 https://zhuanlan.zhihu.com/p/675127867 Garbage Collection&#xff0c;缩写为GC&#xff0c;一种内存管理回收的机制…