我们针对链表中最经典的几道算法题做讲解:
1.求两个链表的公共节点.
2.判断链表是否有环.
3.给定一个链表,判断是否有环,有返回入环的第一个节点,无返回空.(在第二题上的加强版).
4.给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝.
5.对链表进行插入排序.
6.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针.
一.详细讲解
1.求两个链表的公共节点.(如图)
typedef struct ListNode node;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
node* cur1=headA;
node* cur2=headB;
int sum1=0;
int sum2=0;
int before=0;
while(cur1->next){//判断第一个节点的长度,并走到最后一个节点
cur1=cur1->next;
sum1++;
}
while(cur2->next){//判断第二个节点的长度,并走到最后一个节点
cur2=cur2->next;
sum2++;
}
if(cur1!=cur2){//判断最后一个节点是否相等,相等则有公共节点,不相等则没有直接返回.
return NULL;
}
if(sum1>sum2){//判断两个链表那个长,长的那个先走,直到两个距离最后一个节点相同距离.
before=sum1-sum2;
for(int i=0;i<before;i++){
headA=headA->next;
}
}
if(sum2>sum1){//同上
before=sum2-sum1;
for(int i=0;i<before;i++){
headB=headB->next;
}
}
while(headA!=headB){//两个同时向后走当其相等时,这个节点就是公共节点.
headA=headA->next;
headB=headB->next;
}
return headA;
}
2.判断链表是否有环(如图).
typedef struct ListNode node;
bool hasCycle(struct ListNode *head) {
if(NULL==head || NULL==head->next){//判空
return false;
}
node* slow=head;//定义两个快慢指针
node* fast=head;
int temp=0;
while(1){//快指针每次走两步,慢指针每次走一步.
slow=slow->next;
fast=fast->next->next;
if(NULL==fast || NULL==fast->next){//如果可以走到尾部说明无环.
temp=1;
break;
}
if(slow==fast){//如果快慢指针相遇说明有环.
break;
}
}
if(1==temp){
return false;
}else{
return true;
}
}
3.给定一个链表,判断是否有环,有返回入环的第一个节点,无返回空.(在第二题上的加强版)(如图).
typedef struct ListNode node;
struct ListNode *detectCycle(struct ListNode *head) {
node* slow=head;
node* fast=head;
int temp=0;
while(fast!=NULL && fast->next!=NULL){//同上,定义快慢指针判断是否有环.
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
temp=1;
break;
}
}
if(0==temp){//temp为0说明没环,直接返回.
return NULL;
}
node* head2=fast;
while(head2 != head){//有环同时向后走,相遇时便是入环点.
head=head->next;
head2=head2->next;
}
return head2;
}
4.给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝.
https://blog.csdn.net/weixin_49312527/article/details/121598778?spm=1001.2014.3001.5501
5.对链表进行插入排序.
a.定义一个新的空节点,将链表中的第一个直接连到这个空节点上,然后后面的节点依次与新节点后面的节点比较,比其大就向后走,继续比较,如果走到最后则直接连到最后一个节点上,如果比其小则直接连到其前面.等到全部连完,返回新节点的next就是插入排序后的节点的头节点.
typedef struct ListNode Node;
struct ListNode* insertionSortList(struct ListNode* head){
if(NULL==head||NULL==head->next){//判空
return head;
}
Node* no_head=(Node*)malloc(sizeof(Node));
no_head->next=head;
Node* cur=head->next;
head->next=NULL;
Node* Next=NULL;
Node* new_head=NULL;
while(cur!=NULL){//定义一个新的空节点,将链表中的第一个直接连到这个空节点上,然后后面的
//节点依次与新节点后面的节点比较,比其大就向后走,继续比较,如果走到最后则直接连到最后一个节点
//上,如果比其小则直接连到其前面.等到全部连完,返回新节点的next就是插入排序后的节点的头节点.
Next=cur->next;
cur->next=NULL;
new_head=no_head;
while(new_head->next!=NULL){
if(new_head->next->val<cur->val){
new_head=new_head->next;
}else{
break;
}
}
cur->next=new_head->next;
new_head->next=cur;
cur=Next;
}
return no_head->next;
}
6.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针.
a.首先定义一个空的头节点连接在该链表前,让prv处在no_head(空的头节点),cur处在head(源头节点),如果cur节点不是尾节点,并且与其后面的节点相等,就进入循环一直向后走,找到不相等的节点是结束循环,prv直接连在这,跳过所的相等节点,cur继续放在prv的next处,进行循环判断.如果cur与其后面的不相等,prv和cur同时向后走继续循环判断.
typedef struct ListNode Node;
struct ListNode* deleteDuplication(struct ListNode* pHead ) {
if(NULL==pHead || NULL==pHead->next){
return pHead;
}
Node* no_head=(Node*)malloc(sizeof(Node));
no_head->next=pHead;
Node* prev=no_head;
Node* cur=pHead;
//首先定义一个空的头节点连接在该链表前,让prv处在no_head(空的头节点),cur处在head(源头节点),
//如果cur节点不是尾节点,并
//且与其后面的节点相等,就进入循环一直向后走,找到不相等的节点是结束循环,prv直接连在这,跳过所的
//相等节点,cur继续放在prv的next处,进行循环判断.如果cur与其后面的不相等,prv和cur同时向后走继续
//循环判断.
while(NULL!=cur){
if(cur->next!=NULL && cur->val==cur->next->val){
while(cur->next!=NULL && cur->val==cur->next->val){
cur=cur->next;
}
prev->next=cur->next;
cur=cur->next;
}else{
prev=prev->next;
cur=cur->next;
}
}
return no_head->next;
}