链表面试题(链表能力提升)

第一题

代码如下,主要分为两部分,检查删除部分和迭代部分,删除部分要注意第一个元素为删除的情况。 

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* p = NULL,* cur = head;
   while(cur)
 {
     //1.头删 2.中间删除(与尾删相同)
     if(cur->val==val)
     {
         
         if(cur==head)
         {
             head=cur->next;
             free(cur);
             cur = head;
         }
         else
         {
             p->next=cur->next;
             free(cur);
             cur=p->next;
         }
     }
     else
     {
         //迭代往后走
         p=cur;
         cur=cur->next;
     }
 }
 return head;
}

第二题

 这里有两种解法,第一种是直接用三个指针n1 n2 n3翻转链表, n1为空,n2为第1个节点,n3为n2的后一个节点,首先如果链表为空,则直接返回NULL,翻转环节判断n2是否为NULL,是则退出循环,不是则让n2指向n1,然后往后迭代,要注意n3的迭代可能会出现问题,所以要多加一个条件判断。

struct ListNode* reverseList(struct ListNode* head)
{
  if(head == NULL)
   return NULL;
struct ListNode *n1 , *n2, *n3;
n1 = NULL;
n2 = head;
n3 = head->next;
  while(n2)
{
//翻转
n2->next = n1;
//迭代往后走
n1 = n2;
n2 = n3;
//最后一个节点
if(n3)
n3 = n3->next;
}
return n1;
}

另一种解法,头插法,将节点一个一个重新串起来。

struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur = head;
struct ListNode* newhead = NULL;
while(cur)
{
struct ListNode*next = cur- >next;
/头插
cur->next = newhead;
newhead = cur;
//迭代往后走
cur = next;
}
return newhead;
}

第三题

 

 这里相比遍历一遍链表确定长度以后找出中间节点,用快慢指针的解法更加便利简洁,让快指针一下走两步,慢指针一下一步,当快指针为空或快指针的next为空循环停止,此时慢指针的位置即为中间结点的位置。

struct ListNode *slow, *fast;
slow = fast = head;
   while(fast && fast->next)
 {
    slow = slow->next;
    fast = fast->next->next;
 }
 return slow;

第四题

 题解如下

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
//如果其中一个链表为空,返回另一个
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;
struct ListNode* head=NULL,*tail=NULL;
while(list1 && list2)
{
if(list1->val < list2->val)
{
if( head == NULL)
{
head = tail = list1;
} 
else
{
tail->next = list1;
tail = list1;
}
list1 = list1->next;
}
else
{
if(head == NULL)
{
head = tail = list2;
}
else
{
tail->next = list2;
tail=list2;
}
list2=list2->next;
}
}
if(list1)
{
    tail->next=list1;
}
if(list2)
{
    tail->next=list2;
}
return head;
}

第五题

 这里可以依次用A链表的节点与B链表的所有节点进行比较,找到中间节点,但时间复杂度为O(n^2),较为繁琐,这里另一种方法解题,先遍历两个链,计算出长度,并判断两个最后的结点是否相同,如果相同,则他们是相交的,如果不同则不相交,并return NULL,然后让长链表走长度差,这样两个链表到相同节点的中间的节点数就一样了,只要同时往后走,就可以遇到相同节点。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
int lenA = 1;
while(tailA->next)
{
++lenA;
tailA = tailA->next;
}
int lenB = 1;
while(tailB->next)
{
lenB++;
tailB = tailB->next;
}
if(tailA != tailB)
{
return NULL;
}
int gap = abs( lenA - lenB);
//长的先走差距步,再同时走找交点
struct ListNode* longList = headA;
struct ListNode* shortList = headB;
if( lenA < lenB)
{
shortList = headA;
longList = headB;
}
while(gap--)
{
longList = longList->next;
}
while( longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值