目录
1、链表的回文结构
2、相交链表
3、随机链表的复制
4、环形链表
5、环形链表(||)
6、完结散花
个人主页:秋风起,再归来~
数据结构与算法
个人格言:悟已往之不谏,知来者犹可追
克心守己,律己则安!
1、链表的回文结构
题目描述:
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1返回:true题目链接:OJ链接
解题代码:
ListNode* findMid(ListNode* head)
{
struct ListNode* fast=head,*slow=head;
while(fast)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
ListNode* reverse(ListNode* mid)
{
ListNode* n1=NULL;
ListNode* n2=mid;
ListNode* n3=mid->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
{
n3=n3->next;
}
}
return n1;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code her
//找中间节点
ListNode* mid=findMid(A);
//把中间节点后的节点逆置
ListNode* rmid=reverse(A);
while(A)
{
if(A->val!=rmid->val)
{
return false;
}
A=A->next;
rmid=rmid->next;
}
return true;
}
};
2、相交链表
题目描述:
给你两个单链表的头节点
headA
和headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回null
。图示两个链表在节点
c1
开始相交:题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
intersectVal
- 相交的起始节点的值。如果不存在相交节点,这一值为0
listA
- 第一个链表listB
- 第二个链表skipA
- 在listA
中(从头节点开始)跳到交叉节点的节点数skipB
- 在listB
中(从头节点开始)跳到交叉节点的节点数评测系统将根据这些输入创建链式数据结构,并将两个头节点
headA
和headB
传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 — 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
示例 2:
输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at '2' 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入: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
1 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
- 如果
listA
和listB
没有交点,intersectVal
为0
- 如果
listA
和listB
有交点,intersectVal == listA[skipA] == listB[skipB]
进阶:你能否设计一个时间复杂度
O(m + n)
、仅用O(1)
内存的解决方案?题目链接:OJ链接
解题代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode *tailA=headA,*tailB=headB;
int lenA=0,lenB=0;
while(tailA->next)
{
lenA++;
tailA=tailA->next;
}
while(tailB->next)
{
lenB++;
tailB=tailB->next;
}
if(tailA!=tailB)
return NULL;
int gap=abs(lenA-lenB);//差距步
//假设A为长链表
struct ListNode *longList=headA,*shortList=headB;
if(lenA<lenB)
{
longList=headB;
shortList=headA;
}
while(gap--)
{
longList=longList->next;
}
while(longList)
{
if(longList==shortList)
return shortList;
longList=longList->next;
shortList=shortList->next;
}
return NULL;
}
3、随机链表的复制
题目描述:
给你一个长度为
n
的链表,每个节点包含一个额外增加的随机指针random
,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由
n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的next
指针和random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。例如,如果原链表中有
X
和Y
两个节点,其中X.random --> Y
。那么在复制链表中对应的两个节点x
和y
,同样有x.random --> y
。返回复制链表的头节点。
用一个由
n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个[val, random_index]
表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0
到n-1
);如果不指向任何节点,则为null
。你的代码 只 接受原链表的头节点
head
作为传入参数。示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]示例 2:
输入:head = [[1,1],[2,1]] 输出:[[1,1],[2,1]]示例 3:
输入:head = [[3,null],[3,0],[3,null]] 输出:[[3,null],[3,0],[3,null]]提示:
0 <= n <= 1000
-104 <= Node.val <= 104
Node.random
为null
或指向链表中的节点。题目链接:OJ链接
解题代码:
struct Node* copyRandomList(struct Node* head) {
struct Node* cur=head;
//将复制的链表先尾插到原链表的后面
while(cur)
{
struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
copy->val=cur->val;
copy->next=cur->next;
cur->next=copy;
cur=copy->next;
}
//复制链表的random的指向
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;
}
//将复制链表穿起来,并恢复原链表
struct Node* copyhead=NULL,*copytail=NULL;
cur=head;
while(cur)
{
struct Node* copy=cur->next;
struct Node* next=copy->next;
if(copyhead==NULL)
{
copyhead=copytail=copy;
}else{
copytail->next=copy;
copytail=copytail->next;
}
cur->next=next;//恢复原链表
cur=next;
}
return copyhead;
}
4、环形链表
题目描述:
给你一个链表的头节点
head
,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回
true
。 否则,返回false
。示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引 。进阶:你能用
O(1)
(即,常量)内存解决此问题吗?题目链接:OJ链接
解题代码:
bool hasCycle(struct ListNode *head) {
struct ListNode* fast=head,*slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
return true;
}
}
return false;
}
5、环形链表(||)
题目描述:
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos
是-1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。提示:
- 链表中节点的数目范围在范围
[0, 104]
内-105 <= Node.val <= 105
pos
的值为-1
或者链表中的一个有效索引进阶:你是否可以使用
O(1)
空间解决此题?题目链接:OJ链接
解题代码:
struct ListNode * hasCycle(struct ListNode *head) {
struct ListNode* fast=head,*slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
return fast;
}
}
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head) {
if(hasCycle(head)==NULL)
{
return NULL;
}
else
{
struct ListNode* meet=hasCycle(head);
struct ListNode* cur=head;
while(cur)
{
if(cur==meet)
{
return cur;
}
cur=cur->next;
meet=meet->next;
}
}
return NULL;
}
6、完结散花
好了,这期的分享到这里就结束了~
如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~
我们下期不见不散~~