代码随想录算法day4 - 链表2

news/2024/10/5 5:11:40

题目1 24. 两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

img

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100]
  • 0 <= Node.val <= 100

思路

无虚拟头

这道题中每次交换两个节点时要改变三个指针的指向,所以我们需要三个变量来记录这三个相邻节点。在第一次交换节点(在满足节点数量>=2)时需要注意只需要更改头节点和后一个节点就行了,第一次交换节点只需要两个节点,之后的交换才需要三个节点。

代码

class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr){return head;}ListNode* preNode = head;//如果节点有两个以上,则移动头指针到第二个节点if(head->next != nullptr){head = head->next;}else{return head;}ListNode* ppreNode = nullptr;ListNode* curNode = preNode->next;for(int i = 0; curNode != nullptr; i++){//i % 2 == 0判断表示隔一个节点后进行两两交换if(i % 2 == 0){ListNode* tmpNode = curNode->next;curNode->next = preNode;preNode->next = tmpNode;if(ppreNode != nullptr)ppreNode->next = curNode;curNode = tmpNode;}else{ppreNode = preNode;preNode = curNode;curNode = curNode->next;}}return head;}
};

有虚拟头

有虚拟头的情况比无虚拟头简单,因为不用额外考虑第一次只修改两次指针的情况,所有交换的情况都是三个指针进行操作。要注意的就是在实际项目中要在返回前释放掉虚拟头节点的内存,避免内存泄漏。

class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head == nullptr || head->next == nullptr){return head;}ListNode* dumNode = new ListNode(-1, head);ListNode* ppreNode = dumNode,* preNode  = dumNode->next,* curNode  = preNode->next;while(curNode != nullptr){ppreNode->next = curNode;ListNode* tmpNode = curNode->next;curNode->next = preNode;preNode->next = tmpNode;if(tmpNode != nullptr && tmpNode->next != nullptr){ppreNode = preNode;preNode = tmpNode;curNode = tmpNode->next;}else{break;}}head = dumNode->next;delete dumNode;return head;}
};

题目2 19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

img

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

思路

暴力迭代法(两轮遍历)

暴力迭代法通过遍历两轮链表来删除倒数第n个节点,第一轮用来计算链表的节点总数,第二轮用于命中目标节点与前一个节点来进行删除操作。

额外指针数组(一轮遍历)

因为题目中给出了结点的数量范围,因此创建一个固定大小的listNode指针数组,用一轮遍历统计结点总数并将结点按序放入到数组中。之后通过计算能命中倒数第n个节点的位置,最终通过指针数组来删除指针。

代码

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {if(head == nullptr){return head;}ListNode* curNode = new ListNode(0, head);ListNode* lst[32];lst[0] = curNode;int num = 0;for(; curNode != nullptr; num++){curNode = curNode->next;lst[num + 1] = curNode;}//goal + n = num - > goal = num - n//num - n为要删除的节点位置,对其-1和+1为前和后结点lst[num - n - 1]->next = lst[num - n + 1];delete lst[num - n];head = lst[0]->next;delete lst[0];return head;}
};

双指针法

假设链表长度是n(n > 0),要删除的结点时倒数第y( 0 < y <= n )个,左指针的位置为lft,右指针的位置为rht,在链表前用额外的结点(dummyNode)指向链表头。让lft和rht的初始位置都为dummyNode,先让rht向后面的结点移动y次,此时lft和rht的正好相差y个结点。之后同时让lft和rht向后面结点移动,直到rht指向为空终止,此时lft对应的指针指向的正好是倒数第y个结点。因此如果想删除第n个结点就需要倒数第n+1个结点的位置,代码也因此能写出来。

代码

class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummyNode = new ListNode(0, head);ListNode* lft = dummyNode,* rht = dummyNode;for(int i = 0; i <= n; i++){rht = rht->next;}while(rht != nullptr){lft = lft->next;rht = rht->next;}lft->next = lft->next->next;head = dummyNode->next;delete dummyNode;return head;}
};

题目3 07. 链表相交

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null

图示两个链表在节点 c1 开始相交

img

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

示例 1:

img

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:

img

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

img

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 0 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listAlistB 没有交点,intersectVal0
  • 如果 listAlistB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思路

这道题只要将两个链表的尾部对齐就好做了,首先判断两个链表的长短并在第一次遍历结束后通过最后一个结点判断两链表是否相交,若相交则用指针指向长链表的子链表结点,使得子链表长度和另一个短链表长度一致,最后一一比较就找到了相交的结点。

代码

class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {if(headA == nullptr || headB == nullptr){return nullptr;}ListNode* aNode = headA,* bNode = headB;int lenA = 0, lenB = 0;while(aNode->next != nullptr){aNode = aNode->next;lenA++;}while(bNode->next != nullptr){bNode = bNode->next;lenB++;}if(aNode != bNode){return nullptr;}int len;
#define FIND_UNODE(LLIST, SLIST, LLEN, SLEN, LEN)\LEN = LLEN - SLEN;                       \while(LEN--){                            \LLIST = LLIST->next;                 \}                                        \while(LLIST != SLIST){                   \LLIST= LLIST->next;                  \SLIST = SLIST->next;                 \}                  if(lenA > lenB){FIND_UNODE(headA, headB, lenA, lenB, len);}else{FIND_UNODE(headB, headA, lenB, lenA, len);}
#undef FIND_UNODEreturn headA;}
};

题目4 142. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

img

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

img

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

img

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104]
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

进阶:你是否可以使用 O(1) 空间解决此题?

思路

双指针

这道题更像是数学计算题。。。利用双指针中快指针的一次多步和慢指针的一次一步来遍历整个链表,直到两个指针相遇,最后在通过新指针和快指针的进一步遍历及相遇来确定环的入口。

代码

class Solution {
public:ListNode *detectCycle(ListNode *head) {if(head == nullptr){return head;}ListNode* fast = head,* slow = head;while(fast->next != nullptr && fast->next->next != nullptr){fast = fast->next->next;slow = slow->next;if(slow == fast){ListNode* markNode = head;while(markNode != fast){markNode = markNode->next;fast = fast->next;}return markNode;}}return nullptr;}
};

set集合筛选法

众所周知,在C++里有set模板类可以筛除重复的元素,我们用这个类保存链表里的所有结点,并对每一次插值前和插值后比较set对象的总数,若set对象总数没发生变化就说明已经进入环入口。使用这种方法要额外消耗内存,但在接近最坏的情况时(即链表非常长,环也很大的情况下,用这种方法能节省最后双指针法寻找遍历的时间)。

代码

class Solution {
public:ListNode *detectCycle(ListNode *head) {if(head == nullptr){return head;}set<ListNode*> roundSet;int preNum = INT_MAX;while(head != nullptr){preNum = roundSet.size();roundSet.insert(head);if(preNum == roundSet.size())break;head = head->next;}return head;}
};

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

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

相关文章

【Shell脚本】查看Linux网卡实时流量

原创 唐哥 成长的小学生在Linux操作系统中,查询网卡流量并不是特别方便,而且统计方式也不直观,下面给大家整理了一个脚本,直接复制到服务器上运行即可,不存在什么依赖关系。脚本内容 将内容保存到一个文件中,文件名称可以自定义,比如:vi catnet.sh将以下内容保存到脚本…

.Net 5.0 WebAPI 发布至 CentOS 7 系统

本文先安装 .net 5.0 的环境,再创建一个示例项目并发布至 CentOS 上,同时列明了一些注意的点;最后将 dotnet 命令添加到系统自启动服务。〇、前言 本文主要介绍了在 CentOS 7 上部署 WebAPI 项目的过程。 先安装 .net 5.0 的环境,再创建一个示例项目并发布至 CentOS 上,同…

高德地图,只有部分marker显示InfoWindow并可点击

高德地图,只有部分marker显示InfoWindow并可点击 原因: 加了 MarkerCluster 之后,出现不稳定现象“有部分marker显示InfoWindow并可点击”。// 将所有的标记点添加到marker cluster // marker cluster// markerLayer.setMarkers(markers); // marker cluster // th…

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

背景 OSN 是一种 fee on transfer 代币,会根据用户分红账户的余额对用户发放分红。攻击者利用漏洞增发分红账户的余额,随后触发分红机制完成获利。 OSN:https://bscscan.com/address/0x810f4c6ae97bcc66da5ae6383cc31bd3670f6d13#code 攻击由三笔交易组成:https://app.bloc…

IDEA 使用教程

概述 视频教程:【尚硅谷IDEA安装idea实战教程(百万播放,新版来袭)】 jetbrains 中文官网 IDEA 官网 IDEA 从 IDEA 2022.1 版本开始支持 JDK 17,也就是说如果想要使用 JDK 17,那么就要下载 IDEA 2022.1 或者之后的版本。 Jetbrains 公司旗下还有其它产品,比如:WebStorm:…

[Redis]Intset

intset 小整数集合 set 集合容纳的元素都是整数并且元素个数较少时, Redis 会使用 intset 来存储集合元素。 intset 是紧凑的数组结构,同时支持 16 位、 32 位和 64 位整数 struct intset<T> {int32 encoding;//决定整数位宽是 16 位、 32 位还是 64int32 length ;//元…

Github祝你有美好的一天:Have an Octotastic day!

Thanks for submitting! Be sure to check your email. If you dont hear from us within the hour, you should receive an email from us in less than 8 days. Have an Octotastic day! 它来自 Github 服务。Github 的标志是一个 Octocat(如图所示),这句话可能类似于“祝…

第3天---RSA基础题型(二)

前言: 量是一定要积累的,但是不要一味的追求量,导致学完后面的知识,忘了前面的知识,得不偿失,那我们当然要避免这种情况,那就先花点时间复习昨天的内容。 ........ ........ 过了10min T9.添加小因子(e与phi不互素) 一.题目: from Crypto.Util.number import *flag =…