链表问题主要通过双指针解决,
1. 链表中倒数第K个节点
核心:生成两个指针;指针1用于停止,一开始先一直往后遍历,遍历到第K个时,指针2开始遍历,这时候指针1和2之间的距离便是K,当指针1遍历到链表结束时,指针2停止,停止处便是原链表倒数第K个节点;
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* list1 = pListHead;
ListNode* list2 = pListHead;
int i;
for(i=0;list1!=NULL;i++){
if(i>=k)
list2 = list2->next;
list1 = list1->next;
}
return (i>=k)?list2:NULL;
}
};
2、反转链表
核心:生成两个node节点,一个用于遍历,另一个用于存储之前的遍历;具体代码参考如下
class Solution{
public:
ListNode* ReverseList(ListNode* pHead){
ListNode* pNode=pHead;
ListNode* pPre=NULL;
while(pNode!=NULL){
ListNode* pNext=pNode->next;
pNode->next=pPre;
pPre=pNode;
pNode=pNext;
}
return pPre;
}
};
3、合并两个排序链表
核心:
1、生成新的链表
2、比较两个排序链表指向位置的值的大小,将小的值接在新的链表后面
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* head = new ListNode(0);
ListNode* p = head;
if (l1 == NULL) return l2;
if (l2 == NULL) return l1;
while (l1 && l2) {
if (l1 -> val <= l2 -> val) {
head -> next = l1;
l1 = l1 -> next;
}
else {
head -> next = l2;
l2 = l2 -> next;
}
head = head -> next;
}
if (l1) {
head -> next = l1;
}
else {
head -> next = l2;
}
return p -> next;
}
};
4、复杂链表的复制
核心:分为3步
- 复制节点
- 复制随机指针
- 拆分节点
/*
Struct RandomListNdoe{
int label;
struct RandomListNode *next,*random;
RandomListNode(int) :
label(x),next(NULL),random(BULL){
}
};
*/
class Solution{
RandomListNode* Clone(RandomListNode* pHead){
if(pHead==NULL)
return NULL;
//复制节点
RandomListNode* currNode=pHead;
while(currNode){
RandomListNode* newNode=new RandomListNode(currNode->label);
newNode->next=currNode->next;
currNode->next=newNode;
currNode=newNode->next;
}
//复制随机指针
currNode=pHead;
while(currNode){
RandomListNode* newNode=currNode->next;
if(currNode->random)
newNode->random=currNode->random->next;
currNode=newNode->next;
}
//拆分
currNode=pHead;
RandomListNode* pClone=currNode->next;
while(currNode->next){
RandomListNode* newNode=currNode->next;
currNode->next=newNode->next;
currNode=newNode;
}
return pClone;
}
};
5、两个链表的第一个公共节点
核心:
- 两个指针,指向两个链表的头节点
- 当两个指针不同时,对每一个指针,判断其是否为空,为空则指向另一个链表的头节点,否则指向下一个节点
class Solution{
public:
ListNode* FindFirstCommonNode(ListNode* pHead1,ListNode* pHead2){
ListNode *p1=pHead1;
ListNode *p2=Phead2;
while(p1!=P2){
p1=(p1==NULL?pHead2:p1->next);
p2=(p2==NULL?pHead1:p2->next);
}
return p2;
}
};
6、链表中环的入口节点
问题:找出一个链表中环的入口节点
class Solution{
public:
ListNode* EntryNodeOfLoop(ListNode* pHead){
if(pHead==NULL || pHead->next==NULL)
return NULL;
ListNode* p1=pHead;
ListNode* p2=pHead;
while(p2!=NULL && p2->next!=NULL){
p1=p1->next;
p2=p2->next->next;
if(p1==p2){
p2=pHead;
while(p1!=p2){
p1=p1->next;
p2=p2->next;
}
if(p1==p2)
return p1;
}
}
return NULL;
}
};
7、删除链表中的重复节点
问题:删除链表中的重复节点,重复节点也不保留
思路:双指针遍历
- 一个指针用于从前往后遍历
- 在指针的下一个位置处,开始另一个指针的遍历,遍历到不相等的节点后,更新
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* p = head;
while (p != nullptr && p->next != nullptr) {
ListNode* t = p->next;
while (t != nullptr && p->val == t->val) {
t = t->next;
}
p->next = t;
p = t;
}
return head;
}
};