目录
一、回文链表
1.1 题目
牛客网原题链接:链表的回文结构_牛客题霸_牛客网
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
1.2 题解
class PalindromeList {
public:
//寻找中间节点
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
//逆置链表
struct ListNode* reverseList(struct ListNode* head) {
if (head == NULL) {
return head;
}
struct ListNode* a = NULL;
struct ListNode* b = head;
struct ListNode* c = head->next;
while (b) {
b->next = a;
a = b;
b = c;
if (c) {
c = c->next;
}
}
return a;
}
//
bool chkPalindrome(ListNode* A) {
struct ListNode* mid = middleNode(A);
struct ListNode* rmid = reverseList(mid);
while(rmid&&A)
{
if(rmid->val!=A->val)
{
return false;
}
rmid=rmid->next;
A = A->next;
}
return true;
}
};
1.3 分析
找到中间节点,将中间节点往后的节点进行逆置,然后从中间节点开始遍历之后的节点与头节点进行比较。
寻找中间节点使用快慢指针法,逆置链表用三指针法。具体讲解详见博主的另一篇博客:http://t.csdnimg.cn/1mZ1x
二、带环链表I
2.1 题目
LeetCode原题链接:. - 力扣(LeetCode)
给你一个链表的头节点
head
,判断链表中是否有环。如果链表中存在环 ,则返回true
。 否则,返回false
。
2.2 题解
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
return true;
}
}
return false;
}
2.3 分析
2.3.1为什么该思路可行?
2.3.2为什么只能快指针走两步?
三、带环链表II
3.1 题目
LeetCode原题链接:. - 力扣(LeetCode)
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。
3.2 题解
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
{
struct ListNode* meet = slow;
while(meet!=head)
{
meet=meet->next;
head=head->next;
}
return meet;
}
}
return false;
}
3.3 分析
四、相交链表
4.1 题目
LeetCode原题链接:. - 力扣(LeetCode)
给你两个单链表的头节点
headA
和headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回null
。
4.2 题解
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA=headA,*curB=headB;
struct ListNode* plong=headA,*pshort=headB;
int kA=0;
int kB = 0;
while(curA->next)
{
curA=curA->next;
kA++;
}
while(curB->next)
{
curB=curB->next;
kB++;
}
if(curA!=curB)
{
return NULL;
}
int cha = abs(kA-kB);
if(kA<kB)
{
plong = headB;
pshort=headA;
}
while(cha--)
{
plong=plong->next;
}
while(plong!=pshort)
{
plong=plong->next;
pshort=pshort->next;
}
return plong;
}
4.3 分析
4.3.1如何判断是相交链表
两个链表的尾指针指向的是同一个节点
4.3.2如何返回相交节点
难点:相交前的两个链表长度可能不同,不能从头开始一一比较
解决方案:将长链表的指针率先走,走到长度与短链表的指针相同为止。
采用快慢指针法。详见博主的另一篇博客:http://t.csdnimg.cn/1mZ1x
4.4第三题的相交链表新思路
五、面试题—链表的深度拷贝
5.1 题目
LeetCode原题链接:. - 力扣(LeetCode)
给你一个长度为
n
的链表,每个节点包含一个额外增加的随机指针random
,该指针可以指向链表中的任何节点或空节点。
5.2 题解
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;
}
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;
}
cur = head;
//构建新链表并返回
struct Node* copyhead=NULL;
struct Node* copytail=NULL;
while(cur)
{
struct Node* copy = cur->next;
if(copyhead==NULL)
{
copyhead=copytail=copy;
}
else
{
copytail->next=copy;
copytail=copytail->next;
}
cur=copy->next;
}
return copyhead;
}
5.3 分析
难点:随机指针的指向问题
解决方案:
1. 复制一个全新链表,根据原链表的相对位置,确定随机指针的指向,时间复杂度为O(N^2)
2.将每个新节点全部尾插到原节点的后面,这样只需将random指向原节点的next的指针即可。