目录
一、回文链表
1.1 题目
1.2 题解
1.3 分析
二、带环链表I
2.1 题目
2.2 题解
2.3 分析
2.3.1为什么该思路可行?
2.3.2为什么只能快指针走两步?
三、带环链表II
3.1 题目
3.2 题解
3.3 分析
四、相交链表
4.1 题目
4.2 题解
4.3 分析
4.3.1如何判断是相交链表
4.3.2如何返回相交节点
4.4第三题的相交链表新思路
五、面试题—链表的深度拷贝
5.1 题目
5.2 题解
5.3 分析
一、回文链表
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的指针即可。