链表 oj2 (7.31)

2023-10-18 20:20
文章标签 链表 7.31 oj2

本文主要是介绍链表 oj2 (7.31),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

206. 反转链表 - 力扣(LeetCode)

我们通过头插来实现

将链表上的节点取下来(取的时候需要记录下一个节点),形成新的链表,对新的链表进行头插。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* reverseList(struct ListNode* head)
{//用cur对原链表进行遍历struct ListNode* cur=head,*newhead=NULL;//原链表为空,遍历结束while(cur){//记录cur的下一个节点struct ListNode* next=cur->next;//cur链接到新链表cur->next=newhead;//cur成为新链表的头指针newhead=cur;//cur通过next在原链表中向后移cur=next;}return newhead;
}

21. 合并两个有序链表 - 力扣(LeetCode)

这里需要引用哨兵位,先介绍一下

    

哨兵位就是不带数据的头节点,且为固定的节点,当链表为空时,带哨兵位的链表(右)存在一个头节点(空间),而不带哨兵位的链表(左)则没有节点。

更改带哨兵位的链表(增删查改)就不需要判断,通过二重指针改变头指针,通过 next 就能直接实现。

使用的时候为哨兵位申请一块动态内存,作为头节点,结束的时候可以根据题目要求将其释放。

实现:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1==NULL){return list2;}if(list2==NULL){return list1;}struct ListNode* head=NULL,*tail=NULL;//带一个哨兵位,方便尾插head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));while(list1&&list2){if(list1->val<list2->val){tail->next=list1;tail=tail->next;list1=list1->next;}else{tail->next=list2;tail=tail->next;list2=list2->next;}}//if(list2){tail->next=list2;}if(list1){tail->next=list1;}//哨兵位的头使用完需要释放掉struct ListNode* del=head;head=head->next;free(del);return head;
}

链表分割_牛客题霸_牛客网 (nowcoder.com)

思路是创建两个链表,将小于 x 的尾插到第一个链表,大于 x 尾插到第二个链表。

此题目用带哨兵位的链表做更加简单,因为尾插时不用考虑链表是否为空的情况,将两个链表链接的时候也不需要考虑其中一个链表为空的情况了(即不用担心链表为空的情况)。

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
#include <cstddef>
class Partition {public:ListNode* partition(ListNode* pHead, int x) {struct ListNode* ghead, *gtail, *lhead, *ltail;ghead = gtail = (struct ListNode*)malloc(sizeof(struct ListNode));lhead = ltail = (struct ListNode*)malloc(sizeof(struct ListNode));//用cur遍历struct ListNode* cur = pHead;while (cur){if(cur->val < x){ltail->next = cur;ltail = ltail->next;}else{gtail->next = cur;gtail = gtail->next;}cur = cur->next;}//将低链表的尾链接到高链表的哨兵位之后的节点ltail->next = ghead->next;//将目标链表的尾置空,否则产生环gtail->next = nullptr;//拷贝目标链表的头节点struct ListNode* head = lhead->next;//释放哨兵位free(lhead);free(ghead);return head;}
};

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

回文结构就是对称的意思,例如 1 2 2 1,1 2 3 2 1。

结合前面的 oj 题目,我们容易想到一个方法,先找出链表的后半段,然后将其逆置,再将其与前半段比较,如果都相同,则为回文结构。

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public://反转链表struct ListNode* reverseList(struct ListNode* head)
{//用cur对原链表进行遍历struct ListNode* cur=head,*newhead=nullptr;//原链表为空,遍历结束while(cur){//记录cur的下一个节点struct ListNode* next=cur->next;//cur链接到新链表cur->next=newhead;//cur成为新链表的头指针newhead=cur;//cur通过next在原链表中向后移cur=next;}return newhead;
}//找出中间节点struct ListNode* middleNode(struct ListNode* head){struct ListNode* slow=head,*fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;
}bool chkPalindrome(ListNode* head) {//找出后半段struct ListNode* mid=middleNode(head);//将后半段逆置struct ListNode* rmid=reverseList(mid);while(rmid&&head){if(rmid->val!=head->val){return false;}rmid=rmid->next;head=head->next;}return true;}
};

160. 相交链表 - 力扣(LeetCode)

思路:

1.遍历计算出A,B链表各自的长度 lenA,lenB

2.长的链表走差距步 lenA-lenB,此时两条链表的长度相同

3.同时移动找交点(指针相同),最后返回这个交点。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* curA=headA,*curB=headB;int lenA=1,lenB=1;//提示了链表不为空,因此结尾用下一个节点判断,同时初始长度为1while(curA->next){curA=curA->next;lenA++;}while(curB->next){curB=curB->next;lenB++;}//尾节点不同,一定没有交点if(curA !=curB){return NULL;}struct ListNode* longList=headA,*shortList=headB;if(lenA<lenB){longList=headB;shortList=headA;}//算出差距步(绝对值)int gap=abs(lenA-lenB);//长的先走差距步while(gap--){longList=longList->next;}//同时走找交点,相等就找到了while(longList !=shortList){longList=longList->next;shortList=shortList->next;}return longList;
}

141. 环形链表 - 力扣(LeetCode)

链表有循环或者非循环

循环链表的尾节点指向头节点。

还有一种带环链表,它的尾节点可以指向链表的任意一个节点(包括自己)。

带环链表中的节点会重复出现,我们依然定义一快一慢指针,如果是带环链表,那么快指针一定能追上慢指针,两个指针一定有相等的时候(追及问题);如果不带环,直接就遍历到空了。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
bool hasCycle(struct ListNode *head) {struct ListNode* fast=head,*slow=head;//链表可能不为环形while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(slow==fast){return true;}}return false;
}

由带环追及问题引发的思考:

1.slow走一步,fast走两步,一定能追上吗,会不会错过?

2.slow走一步,fast走n步(n>=3),一定能追上吗,会不会错过?

如果 slow 走一步,fast 走三步,假设 slow 入环时,slow 和 fast 的距离为 M,每移动(追击)一次,距离缩小2,若 M 为偶数,则当距离减为0时,刚好追上;若 M 为奇数,距离最小时为 -1,即fast 超过了 slow 一步,此时又要观察环的长度C,此时 slow 和 fast 的距离为 C-1,若 C 为奇数,C-1为偶数,那么再经过一轮追击之后就能刚好追上。如果 C 为偶数,那么 C-1 为奇数,奇数-2 永远为奇数,就永远追不上了。 

142. 环形链表 II - 力扣(LeetCode)

分析:

设七点到入口长度:L

环的周长:C

入口点到相遇点的距离:X

fast 走的距离(速度)为 slow 的二倍

slow 进环后的一圈内,fast 一定追上 slow,slow 走的距离为 L+X

slow 进环时,fast 已经走了 n(n>=1) 圈了,fast 走的距离为 L+n*C+X

fast 追赶 slow 之前会先补足 n 圈,

fast 走的距离(速度)为 slow 的二倍可知

2(L+X)=L+n*C+X

同减去L+X

L+X=n*C

L=n*C-X

计算的时候我们默认为 fast 已经跑到 n-1 圈,因此不需要关注 n .

从这个结论我们可以得到从相遇点到环入口点的距离从起点到入口点的距离相同,要想找到入口点,就需要两个指针分别从这两个点开始跑,它们相遇的位置就是入口点。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* fast,*slow;fast=slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;//相遇if(slow==fast){//记录相遇点struct ListNode* meet=slow;//各自从相遇点和头节点开始跑,相遇则为入口点while(head!=meet){head=head->next;meet=meet->next;}return meet;}}//fast或fast的下一个节点为空,说明无环return NULL;
}

法2:

将环从相遇点断开,相遇点之后作为一条新的链表,和旧链表一起找相交点,相交点就是入口点。

这篇关于链表 oj2 (7.31)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/234953

相关文章

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-

建立升序链表

题目1181:遍历链表 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2744 解决:1186 题目描述: 建立一个升序链表并遍历输出。 输入: 输入的每个案例中第一行包括1个整数:n(1<=n<=1000),接下来的一行包括n个整数。 输出: 可能有多组测试数据,对于每组数据, 将n个整数建立升序链表,之后遍历链表并输出。 样例输

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结,删除链表节点问题使用到列表,哈希表,递归比较容易超时,我觉得使用计数排序比较稳,处理起来也不是很难。 1. 力扣3217:从链表中移除在数组中的节点 1.1 题目: 给你一个整数数组 nums 和一个链表的头节点 head。从链表中移除所有存在于 nums 中的节点后,返回修改后的链表的头节点。 示例 1: 输入: nums = [1,2,3], head = [1,2,3,

c++ 链表详细介绍

链表是数据结构的一种,由节点组成,每个节点包含数据和指向下一个节点的指针。链表在C++中的实现可以是单链表、双链表或循环链表。以下是链表的详细介绍: 1. 单链表 结构: 节点(Node):每个节点包含数据和一个指针(next),指向链表中的下一个节点。 示例结构: struct Node {int data;Node* next;Node(int d) : data(d), next(

带头结点的线性链表的基本操作

持续了好久,终于有了这篇博客,链表的操作需要借助图像模型进行反复学习,这里尽可能的整理并记录下自己的思考,以备后面复习,和大家分享。需要说明的是,我们从实际应用角度出发重新定义了线性表。 一. 定义 从上一篇文章可以看到,由于链表在空间的合理利用上和插入、删除时不需要移动等优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在某些实现的缺点,如求线性表的长度时不如顺序存储结构的

数据结构基础(栈,队列,数组,链表,树)

栈:后进先出,先进后出 队列:先进先出,后进后出 数组:查询速度快,通过地址值和索引定位,查询任意数据消耗时长相同,在内存中是连续存储的,删除效率低,要将原始数据删除,然后后面的数据前移,添加效率低,添加索引位置的元素,剩下的都需要向前后移动 链表:节点的存储位置(地址)里面存储本身的数据值,和下一个节点的地址值,链表中的节点是独立对象,在内存中是不连续的。查询速度慢,无论查询哪个数据都要从

(六十四)第 10 章 内部排序(静态链表的插入排序)

示例代码 staticLinkList.h // 静态链表的插入排序实现头文件#ifndef STATIC_LINK_LIST_H#define STATIC_LINK_LIST_H#include "errorRecord.h"#define SIZE 100#define NUM 8typedef int InfoType;typedef int KeyType;ty