当前位置: 首页 > news >正文

数据结构之链表笔试题详解

一:移除链表元素

我们很容易就可以想到一个解决方案:再创建一个链表,把不是val的结点拿过来尾插。

这样确实可以但是,我们每次尾插都需要遍历一遍整个链表,这样时间复杂度就变成了O(n^2),

因此我们不妨设置一个tail尾结点来指向它的尾。

画图分析

这里面还有一个潜在的问题就是,假如最后一个节点的数值==val怎么办,想一想。

完整代码:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {ListNode* newhead;ListNode* newtail;ListNode* pcur = head;newhead=newtail=NULL;while(pcur){if(pcur->val!=val){if(newhead==NULL){newhead=newtail=pcur;}else{newtail->next=pcur;newtail=pcur;}}pcur=pcur->next;}if(newtail!=NULL&&newtail->next!=NULL){newtail->next=NULL;}return newhead;
}

二:反转链表

这一题有两种解法:

解法一:

直接反转指向,比如原来二指向三,现在让三指向2.

画图分析:

经过分析我们写出了这样的代码:

struct ListNode* reverseList(struct ListNode* head) {

    struct ListNode* pprev = NULL;

    struct ListNode* pcur = head;

    struct ListNode* pnext = head->next;

    while(pcur)

    {

        pcur->next=pprev;

        pprev=pcur;

        pcur=pnext;

        pnext=pnext->next;

    }

    return pprev;

}

放在力扣上提交

遇到错误不要慌张,我们看一下提示信息,可以发现,原来是对NULL解引用了,所以在17行那要加上判断,那么说到这了万一这个链表原来就是空呢?因此在一开始也要对这种情况处理。

完整代码:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* pprev = NULL;struct ListNode* pcur = head;struct ListNode* pnext;if(head){pnext = head->next;}while(pcur){pcur->next=pprev;pprev=pcur;pcur=pnext;if(pnext){pnext=pnext->next;}}return pprev;
}

解法二:

取原链表中元素,头插到新链表的newhead中。

画图分析:

完整代码:

struct ListNode* reverseList(struct ListNode* head) {struct ListNode* pcur = head;struct ListNode* newhead = NULL;struct ListNode* pnext;if(head){pnext=head->next;}while(pcur){pcur->next = newhead;newhead = pcur;pcur = pnext;if(pnext){pnext = pnext->next;}}return newhead;
}

三:链表的倒数k个结点

我们确实可以先遍历一遍拿到链表长度,然后就可以找到倒数k个结点了。但是如果只能这么做就没有拿出来的必要了qwq。

快慢指针法:两个指针先让一个走k,然后一起走,等到k指向空(具体看下面画图分析)结束。

画图分析:

完整代码:

struct ListNode* FindKthToTail(struct ListNode* pHead, int k ) {struct ListNode* slow;struct ListNode* fast;slow=fast=pHead;while(k--){if(fast){fast=fast->next;}else {return NULL;}}while(fast){slow=slow->next;fast=fast->next;}return slow;
}

四:链表的中间结点

这题同样也是快慢指针法,大体思路是让fast走两步,slow走一步,但是直觉告诉我们结点数的奇偶性会影响结束条件。

画图分析:

完整代码:

struct ListNode* middleNode(struct ListNode* head) {struct ListNode* slow;struct ListNode* fast;fast=slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;
}

五:合并两个有序链表

思路:依次比较链表中的结点,然后插入小的结点

画图分析:

完整代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {struct ListNode* newhead;struct ListNode* newtail;newhead=newtail=NULL;struct ListNode* pcur1=list1;struct ListNode* pcur2=list2;if(pcur1==NULL)return pcur2;if(pcur2==NULL)return pcur1;while(pcur1&&pcur2){if(pcur1->val<pcur2->val){if(newhead==NULL){   newhead=newtail=pcur1;}else{newtail->next=pcur1;newtail=pcur1;}pcur1=pcur1->next;}else{if(newhead==NULL){   newhead=newtail=pcur2;}else{newtail->next=pcur2;newtail=pcur2;}pcur2=pcur2->next;}}if(pcur1!=NULL){newtail->next=pcur1;}if(pcur2!=NULL){newtail->next=pcur2;}return newhead;
}


优化:

我们每次都要对新创建的头结点判断是否为空。

有没有一种方法可以不用判断呢?:设置一个哨兵位就可以了

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {struct ListNode* pcur1=list1;struct ListNode* pcur2=list2;if(pcur1==NULL)return pcur2;if(pcur2==NULL)return pcur1;struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* tail = head;while(pcur1&&pcur2){if(pcur1->val<pcur2->val){tail->next=pcur1;tail=pcur1;pcur1=pcur1->next;}else{tail->next=pcur2;tail=pcur2;pcur2=pcur2->next;}}if(pcur1!=NULL){tail->next=pcur1;}else{tail->next=pcur2;}struct ListNode* newhead=head->next;free(head);return newhead;
}

六:链表分割

这题没给图,直接画图分析:

画图分析:

完整代码:

class Partition {
public:ListNode* partition(ListNode* pHead, int x) {ListNode* lesshead =(ListNode*)malloc(sizeof(ListNode));ListNode* lesstail=lesshead;ListNode* greaterhead=(ListNode*)malloc(sizeof(ListNode));ListNode* greatertail=greaterhead;ListNode* pcur=pHead;if(pcur==NULL)return NULL;while(pcur){if(pcur->val<x){lesstail->next=pcur;lesstail=pcur;}else {greatertail->next=pcur;greatertail=pcur;}pcur=pcur->next;}lesstail->next=greaterhead->next;greatertail->next=NULL;ListNode* newhead=lesshead->next;free(lesshead);free(greaterhead);return newhead;}
};

七:链表回文

首先这一题开一个900的数组也可以过,但是他并不符合空间复杂度O(1)。

然后我们说一下这一题的思路:先找中间结点,然后逆置,最后一一比较。

具体细节,请看下

画图分析:

完整代码:

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
struct ListNode* middleNode(ListNode* A)
{ListNode* slow = A;ListNode* fast = A;while(fast && fast->next){fast=fast->next->next;slow=slow->next;}return slow;
}
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* pprev = NULL;struct ListNode* pcur = head;struct ListNode* pnext;if(head){pnext = head->next;}while(pcur){pcur->next = pprev;pprev = pcur;pcur = pnext;if(pnext){pnext = pnext->next;}}return pprev;
}
class PalindromeList {
public:bool chkPalindrome(ListNode* A) {ListNode* mid = middleNode(A);ListNode* rhead = reverseList(mid);ListNode* curA = A;ListNode* curR = rhead;while(curA && curR){if(curA->val != curR->val){return false;   }else{curA=curA->next;curR=curR->next;}}return true;}
};

八:链表相交

思路:遍历一遍求长度(同时判断是否会相交),长的走差值步,然后一起走直到两指针相同

这一题不可以用逆置做,想一想为什么??

画图分析:

完整代码:


struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* curA = headA;struct ListNode* curB = headB;int lenA = 1; int lenB = 1;while(curA->next){lenA++;curA=curA->next;}while(curB->next){lenB++;curB=curB->next;}if(curA!=curB)return NULL;int gap = abs(lenA-lenB);struct ListNode* longlist = headA;struct ListNode* shortlist = headB;if(lenA < lenB){longlist = headB;shortlist = headA;}while(gap--){longlist=longlist->next;}while(longlist!=shortlist){longlist=longlist->next;shortlist=shortlist->next;}return longlist;
}

九:环形链表1

思路:快慢指针法,slow走1步fast走2步。如果相遇则带环,否则不带环

画图分析:

完整代码:

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

十:环形链表2

这一题有点数学题的意思。还是先说思路:还是先slow与fast走,等到两指针相遇,在再让一个指针从都走,另一个指针从相遇位置走,直到二者再次相遇即为如环点。

画图分析:

完整代码:

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head;struct ListNode* fast = head;while(fast && fast->next){fast=fast->next->next;slow=slow->next;if(slow==fast){struct ListNode* cur = head;struct ListNode* curC = fast;while(cur!=curC){cur=cur->next;curC=curC->next;}return cur;}}return NULL;
}

十一:复杂随机链表的拷贝

这一次最难搞的是random指针。思路也不好想,大家还是借鉴一下大佬的思路吧。

思路:在每个节点后面插入一个一样的节点,定义cur 和 next指针 cur->next->radom=cur->radom->next,然后迭代往后。最后解开插入的结点。

画图分析:

完整代码:


struct Node* copyRandomList(struct Node* head) {struct Node* cur = head;//插入新节点while(cur){struct Node* newnode = (struct Node* )malloc(sizeof(struct Node));newnode->val = cur->val;newnode->next = cur->next;cur->next = newnode;cur = newnode->next;}//处理randomcur = head;while(cur){struct Node* newnode = cur -> next;if(cur->random==NULL){newnode->random = NULL;}else{newnode->random = cur->random->next;}cur = newnode->next;}//取新节点尾插,同时恢复原链表cur = head;struct Node* newhead = NULL;struct Node* newtail = NULL;while(cur){struct Node* newnode = cur->next;struct Node* next = newnode->next;if(newhead==NULL){newhead = newtail = cur->next;}else{newtail->next = newnode;newtail = newnode;}cur->next = newnode->next;cur = newnode->next;}return newhead;
}

相关文章:

数据结构之链表笔试题详解

一&#xff1a;移除链表元素 我们很容易就可以想到一个解决方案&#xff1a;再创建一个链表&#xff0c;把不是val的结点拿过来尾插。 这样确实可以但是&#xff0c;我们每次尾插都需要遍历一遍整个链表&#xff0c;这样时间复杂度就变成了O(n^2)&#xff0c; 因此我们不妨设…...

结构化的Prompt

资源库&#xff1a; AI 提示词-WayToAGI精选高效的AI提示词库&#xff0c;助力创作者和开发者解锁人工智能的潜力。通过我们的提示词和策略&#xff0c;优化您的AI工具使用效率&#xff0c;激发创意思维&#xff0c;提升产出质量。https://www.waytoagi.com/prompts?tag6 结构…...

【数字化】华为数字化转型架构蓝图

导读&#xff1a;华为的数字化转型规划团队在2016年年底基于对愿景的系统诠释&#xff0c;整合出了数字化转型架构蓝图。该蓝图共分为5层&#xff0c;旨在通过数字化转型实现客户交互方式的转变、作战方式的转变、公司各平台业务能力的数字化、服务化以及运营模式的转变。 目录…...

最新全开源IM即时通讯系统源码(PC+WEB+IOS+Android)部署指南

全开源IM&#xff08;即时通讯&#xff09;系统源码部署是一个复杂但系统的过程&#xff0c;涉及多个组件和步骤。以下是一个详细的部署指南&#xff0c;旨在帮助开发者或系统管理员成功部署一个全开源的IM系统&#xff0c;如OpenIM。      IM即时通讯系统源码准备工作   …...

go 跨平台打包

GOARCH‌是Go语言中的一个环境变量&#xff0c;用于指定目标平台的底层架构。在Go的交叉编译过程中&#xff0c;‌GOARCH‌决定了编译出的二进制文件将在哪种硬件架构上运行。 GOARCH的常见值 ‌amd64‌&#xff1a;64位 x86 架构‌386‌&#xff1a;32位 x86 架构‌arm‌&am…...

C++ 给定字符串,然后给出开始要取的位置,返回取到的信息

3 happy new year 7 year 1 new 4 new year year error input #include <stdio.h> #include <string.h> void strmcpy(char* s, char* t, int m); int main() {int repeat, m;char t[1000], s[1000];scanf("%d", &repeat);getchar(); //吸收换行符in…...

【树莓派4B】MindSpore lite 部署demo

一个demo&#xff0c;mindspore lite 部署在树莓派4B ubuntu22.04中&#xff0c;为后续操作开个门&#xff01; 环境 开发环境&#xff1a;wsl-ubuntu22.04分发版部署环境&#xff1a;树莓派4B&#xff0c;操作系统为ubuntu22.04mindspore lite版本&#xff1a;mindspore-li…...

Idea汉化插件Datagrip汉化插件

汉化插件 ‍ ‍ Chinese (Simplified) Language Pack / 中文语言包 ‍ 插件地址 ‍ 安装完了之后,如果还不是中文的怎么办 ‍ 需要手动设置 Seetings -> Appearance & Behavior -> System Settings -> Language and Region -> Language 修改为 [ Chi…...

精彩回顾|Cocos开发者沙龙长沙站

长沙-不一样 Cocos 开发者沙龙长沙站&#xff0c;完全超出了我们的预期&#xff0c;一开始还担心没有太多人报名。最后发现&#xff0c;全场爆满&#xff0c;座无虚席。 <<< 左右滑动见更多 >>> 许多小伙伴曾反馈过&#xff0c;在以往的开发者沙龙回顾文章中…...

算法日记 49 day 图论(A*算法)

这算是算法的最后一篇了&#xff0c;原本A*之前还有一些相关的最短路径算法的&#xff0c;比如dijkstra的堆优化&#xff0c;SPFA等等&#xff0c;但是有些我没看懂&#xff0c;就不写了&#xff0c;用A*做个结尾。 题目&#xff1a;骑士的攻击 127. 骑士的攻击 (kamacoder.co…...

服务器批量清理redis keys,无法适用客户端必须直连的情况

在 Redis 中&#xff0c;批量清理指定模式的键&#xff08;例如 memberCardData:*&#xff09;可以通过多种方法来实现。需要注意的是&#xff0c;Redis 的命令执行是单线程的&#xff0c;因此对大量键进行操作时可能会阻塞服务器。以下是几种常见的方法&#xff1a; shell K…...

Grafana配置告警规则推送企微机器人服务器资源告警

前提 已经部署Grafana&#xff0c;并且dashboard接入数据 大屏编号地址&#xff1a;Node Exporter Full | Grafana Labs 创建企微机器人 备注&#xff1a;群里若有第三方外部人员不能创建 机器人创建完成&#xff0c;记录下来Webhook地址 Grafana配置告警消息模板 {{ define &…...

数字货币金融研究,深度学习虚拟币价格预测 数据集 市值top20 (2014年—2024年)

比特币&#xff0c;以太坊&#xff0c;狗狗币&#xff0c;屎币&#xff0c;模因币 声明 此数据集的目的是 用于数字货币金融研究&#xff0c;深度学习虚拟币价格预测 1、数据集 2014年——2024年 市值top20 比特币&#xff0c;以太坊&#xff0c;屎币&#xff0c;狗狗币交易…...

druid.properties图标是齿轮

一、问题 在IDEA中&#xff0c; druid.properties图标是齿轮 二、原因 2023版本开始&#xff0c;IDEA新的UI的问题 三、解决方法 1、点击右上角的齿轮图标 2、点击Settings 3、Appearance & Behavior---->New UI---->取消勾选“Enable new UI”---->右下角OK 4…...

【图像处理】利用numpy、opencv、python实现车牌检测

| 利用opencv实现车牌检测 整体流程涉及5个部分 图像通道转换对比度增强边缘连接二值化边界区域裁剪 图像通道转换 将RGB图像转换为HSV图像&#xff0c;仅保留V通道。V通道表示颜色的明暗&#xff0c;常用于图像对比度拉伸、直方图均衡化等流程。 原图像&#xff1a; V通…...

ModuleNotFoundError: No module named ‘torchvision.transforms.functional_tensor‘

问题&#xff1a; 运行代码时&#xff0c;报错&#xff1a; … File “/home/xzy/anaconda3/envs/groundinggpt/lib/python3.10/site-packages/pytorchvideo/transforms/augmix.py”, line 6, in from pytorchvideo.transforms.augmentations import ( File “/home/xzy/anac…...

Android无障碍服务监听实现自动点击按钮

原理&#xff1a; 通过监听窗口改变事件&#xff0c;监听目标应用&#xff0c;通过视图ID&#xff08;或文本、或描述、或其他如坐标之类的&#xff09;找到目标视图&#xff0c;使用无障碍动作点击方法点击它 无障碍服务实现&#xff1a; 1、写一个自己的无障碍服务继承Acc…...

Deveco Studio首次编译项目初始化失败

编译项目失败 Ohpm install失败的时候重新使用管理者打开程序 build init 初始化失败遇到了以下报错信息 Installing pnpm8.13.1... npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/pnpm failed, r…...

Redis缓存应用场景【Redis场景上篇】

文章目录 1.缓存基础2.缓存异步场景1.缓存穿透2.缓存击穿3.缓存雪崩总结 3.缓存一致性 1.缓存基础 Redis由于性能高效&#xff0c;通常可以做数据库存储的缓存。一般而言&#xff0c;缓存分为服务端缓存和客户端缓存。缓存有以下三种模式&#xff1a; Cache Aside&#xff08…...

线程与进程基础

文章目录 前言一、 线程与进程1.1 什么是线程与进程&#xff1f;1.2 并发与并行1.3 同步调用与异步调用1.4 为什么要使用多线程&#xff1f; 前言 在学习juc前&#xff0c;需要先对进程和线程之间整体有一个认知。我们之前或多或少接触过&#xff0c;一些特别高大上的概念&…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...