当前位置: 首页 > 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;一些特别高大上的概念&…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...