1、链表中环的入口结点
- 初始化:快指针fast指向头结点, 慢指针slow指向头结点
- 让fast一次走两步, slow一次走一步,第一次相遇在C处,停止
- 然后让fast指向头结点,slow原地不动,让后fast,slow每次走一步,当再次相遇,就是入口结点。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
法一:双指针
ListNode *slow=pHead;
ListNode *fast=pHead;
while(fast && fast->next)//先快慢指针第一次相遇
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast) break;
}
if(!fast || !fast->next) return nullptr;//无环的情况
fast=pHead;//快指针回到表头
while(slow!=fast)//以一样的速度再次相遇的点就是环的入口
{
slow=slow->next;
fast=fast->next;
}
return fast;
法二 :hashset
unordered_set<ListNode*>st;
while(pHead)
{
if(st.find(pHead)==st.end())
st.insert(pHead),pHead=pHead->next;
else return pHead;
}
return nullptr;
}
};
2、判断链表中是否有环
还是双指针,快慢指针一个一次走一步,另一个一次走两步,如果相遇,则有环。(也可以unordered_set)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(!head) return false;
ListNode *slow = head;
ListNode *fast = head;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(slow == fast) return true;
}
return false;
}
};
3、合并两个排序的链表
注意,c++中申请哨兵节点可以用:new [TYPE]*
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
if(!pHead2) return pHead1;
if(!pHead1) return pHead2;
ListNode *head=new ListNode(0); //申请一个哨兵节点
//ListNode *head=nullptr; 段错误,混淆指针与对象,这样写是让head指向一个空指针,而不是一个节点
ListNode *ptr=head;
while(pHead1 && pHead2)
{
if(pHead1->val < pHead2->val) ptr->next=pHead1,pHead1=pHead1->next;
else ptr->next=pHead2,pHead2=pHead2->next;
ptr=ptr->next;
}
while(pHead1) ptr->next=pHead1,pHead1=pHead1->next,ptr=ptr->next;
while(pHead2) ptr->next=pHead2,pHead2=pHead2->next,ptr=ptr->next;
return head->next;
}
};
4、两个链表的第一个公共结点
假如例子如下:
显然第一个公共结点为8,但是链表A头结点到8的长度为2,链表B头结点到8的长度为3,显然不好办?
如果我们能够制造一种理想情况,如下:
这里先假设链表A头结点与结点8的长度 与 链表B头结点与结点8的长度相等,那么就可以用双指针。
初始化:指针ta指向链表A头结点,指针tb指向链表B头结点
如果ta == tb, 说明找到了第一个公共的头结点,直接返回即可。
否则,ta != tb,则++ta,++tb
所以现在的问题就变成,如何让本来长度不相等的变为相等的?
假设链表A长度为a, 链表B的长度为b,此时a != b
但是,a+b == b+a
因此,可以让a+b作为链表A的新长度,b+a作为链表B的新长度。
如图:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode *p1=pHead1, *p2=pHead2;
while(p1 != p2)
{
p1 = p1 ? p1->next : pHead2;
p2 = p2 ? p2->next : pHead1;
}
return p1;
}
};
声明:题目与题解均来源于牛客网 https://www.nowcoder.com/company/home/code/665?codeType=1