现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
解法:该题需要给使用两个头节点简便尾插,把小于x的节点尾插到一条链表中,另外的尾插到另一条链表中。
ListNode* partition(ListNode* pHead, int x) {
// write code here
ListNode* cur=pHead;
ListNode* smallHead=(ListNode*)malloc(sizeof(ListNode));
ListNode* smallTail;
ListNode* bigHead=(ListNode*)malloc(sizeof(ListNode));
ListNode* bigTail;
// smallHead=smallTail=bigHead=bigTail=NULL;
smallTail=smallHead;
bigTail=bigHead;
while (cur) {
if(cur->val<x)
{
smallTail->next=cur;
smallTail=smallTail->next;
}
else {
bigTail->next=cur;
bigTail=bigTail->next;
}
cur=cur->next;
}
bigTail->next=nullptr;
smallTail->next=bigHead->next;
return smallHead->next;
}
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
解法:如果单纯的判断两个链表是否相交,只需要判断他们的尾节点是否相同,但是该题还需要返回它们相交的第一个节点,所以我们需要让长链表先走链表长度的步差步数,再同时走,当它们相同时返回该节点。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
int lenA=0,lenB=0,distance=0;
struct ListNode *cur1=headA;
struct ListNode *cur2=headB;
while(cur1)
{
lenA++;
cur1=cur1->next;
}
cur1=headA;
while(cur2)
{
lenB++;
cur2=cur2->next;
}
cur2=headB;
distance=abs(lenA-lenB);
if(lenA>lenB)
{
while(distance--&&cur1)
{
cur1=cur1->next;
}
}
else
{
while(distance--&&cur2)
{
cur2=cur2->next;
}
}
while(cur1&&cur2)
{
if(cur1==cur2)
return cur1;
cur1=cur1->next;
cur2=cur2->next;
}
return NULL;
}
给你一个链表的头节点 head
,判断链表中是否有环。
该题使用快慢指针解决,一个指针走一步,一个指针走两步,如果可以相遇,则证明有环,它们的步差为1,所以两个指针一定可以相遇。
bool hasCycle(struct ListNode *head) {
if(head==NULL)
return NULL;
struct ListNode *fast=head;
struct ListNode *low=head;
while(fast&&fast->next)
{
low=low->next;
fast=fast->next->next;
if(fast==low)
{
return true;
}
}
return false;
}
4.环形链表 II
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
解法1:数学思路: 假设起点到环入口距离L ,环入口到相遇点的距离X,环周长C 那么慢指针走了L+X,快指针走了L+X+nC,则有L+X+nC =2(L+X) L=nC-x, 如果此时一个从起始开始走,一个从相遇点走,相遇位置就是环的入口
解法2:再相遇点断开该环,此时找出该相遇点下一个节点开始与起始节点开始的链表交点即可。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *low=head;
struct ListNode *cur=head;
while(fast&&fast->next)
{
low=low->next;
fast=fast->next->next;
if(fast==low)
break;
}
if(fast==NULL||fast->next==NULL)
return NULL;
while(cur!=low)
{
cur=cur->next;
low=low->next;
}
return cur;
}
给你一个长度为 n
的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
解法1:暴力求解,使用一个newhead的头节点,先把原来链表节点复制之后插入其中,后面关键是random,我们可以使用两个指针,先用count记录每个节点的random对于头节点的位置,再复制节点的random走相应位置即可。
解法2:我们先将每个节点复制再原来节点的位置之后,再循环将新链表的random指向当前节点random的下一个节点。再把节点断开返回头即可。
struct Node* buyNode(int x)
{
struct Node* newNode=(struct Node*)malloc(sizeof(struct Node));
if(newNode==NULL)
exit(-1);
newNode->val=x;
newNode->next=newNode->random=NULL;
return newNode;
}
struct Node* copyRandomList(struct Node* head) {
/*struct Node* cur=head;
struct Node*newhead,*newtail;
newhead=newtail=buyNode(-1);
while(cur)
{
struct Node* newNode=buyNode(cur->val);
newtail->next=newNode;
newtail=newNode;
cur=cur->next;
}
cur=head;
struct Node* newcur=newhead->next;
while(cur&&newcur)
{
struct Node* pos=head;
int count=0;
while(pos)
{
if(cur->random==pos)
{
break;
}
count++;
pos=pos->next;
}
if(pos==NULL)
{
newcur->random=NULL;
}
else
{
struct Node* newrandom=newhead->next;
while(count--)
{
newrandom=newrandom->next;
}
newcur->random=newrandom;
}
cur=cur->next;
newcur=newcur->next;
}
return newhead->next;*/
if(head==NULL)
{
return NULL;
}
struct Node* cur=head;
struct Node*newhead,*newtail,*copy,*next;
while(cur)
{
copy=buyNode(cur->val);
next=cur->next;
copy->next=next;
cur->next=copy;
cur=next;
}
cur=head;
while(cur)
{
copy=cur->next;
if(cur->random)
{
copy->random=cur->random->next;
}
else
{
copy->random=NULL;
}
cur=cur->next->next;
}
newtail=newhead=head->next;
cur=head->next->next;
head->next=cur;
while(cur)
{
newtail->next=cur->next;
newtail=cur->next;
cur->next=cur->next->next;
cur=cur->next;
}
newtail->next=NULL;
return newhead;
}