Bootstrap

《数据结构》十道链表经典面试题多种方法深度解析

目录

⛰️一、题目解析

🗻1.1删除链表中等于给定值 val 的所有节点(力扣)

🗻1.2反转一个单链表。(力扣)

🗻1.3给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个 中间结点。(力扣)

🗻1.4输出链表中倒数第k个结点。

🗻1.5将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

🗻1.6编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。

🗻1.7 链表的回文结构

🗻1.8输入两个链表,找出它们的第一个公共结点。

🗻1.9给定一个链表,判断链表中是否有环。

🗻1.10给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL


⛰️一、题目解析

🏠1.删除链表中等于给定值 val 的所有节点。
🏠2.反转一个单链表。
🏠3.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个 中间结点。
🏠4.输出链表中倒数第k个结点。
🏠5.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
🏠6.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
🏠7.链表的回文结构。
🏠8.输入两个链表,找出它们的第一个公共结点。
🏠9.给定一个链表,判断链表中是否有环。
🏠10.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL

🗻1.1删除链表中等于给定值 val 的所有节点(力扣)

 ⚓思路一:剔除某些值,反之,保留某些值。

将不等于val的节点全都尾插至新的链表中,然后返回新的头节点。

细节:

新的链表尾指针需指向空

否则遇到1->2->3->6->5->8->6   val=6。这种情况会有问题。

因为tail的最后的指向是8,而8指向6,6指向空。

最后的错误输出是1->2->3->5->8->6。

解决:在cur退出循环的时候,将tail->next=NULL。但要保证前题tail不为空。

代码:

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* newhead=NULL;
    struct ListNode* newtail=NULL;
    struct ListNode* cur=head;
    while(cur)
    {
        if(cur->val!=val)
        {
            //将节点尾插至新链表
            if(newhead==NULL)
            {
                newhead=newtail=cur;
            }
            else
            {
                newtail->next=cur;
                newtail=cur;
            }
        }
        cur=cur->next;
        if(cur==NULL)
        {
            if(newtail)
                newtail->next=NULL;
        }
    }
    return newhead;
}
⚓思路二:在原链表中操作,找到等于val值的节点,在删除它,这种删除就是把它前一个指针的指向后一个节点的地址。
图解:

 细节:

当要删除的节点为头节点时,prev==NULL。

struct ListNode* temp=cur;

cur=cur->next;

prev->next=cur;(对空指针解引用,发生错误)。

free(temp);

解决:

分情况讨论,当要删除的节点是头节点时。执行以下操作。

 cur=cur->next;

 free(newhead);

newhead=cur;

代码: 

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
    if(head==NULL)
    {
        return head;
    }
    struct ListNode* prev=NULL;
    struct ListNode* newhead=head;
    struct ListNode* cur=head;
    while(cur)
    {
        if(cur->val==val)
        {
            if(cur==newhead)
            {
                cur=cur->next;
                free(newhead);
                newhead=cur;
            }
            else
            {
                struct ListNode* temp=cur;
                cur=cur->next;
                prev->next=cur;
                free(temp);
            }
        }
        else
        {
            prev=cur;
            cur=cur->next;
        }
    }
    return newhead;
}

🗻1.2反转一个单链表。(力扣)

 ⚓思路一:

三指针法:前指针 中指针 后指针

翻转部分:中指针指向前指针

迭代部分:前指针=中指针;中指针=后指针;后指针=后指针->next。

图解:

细节:

最后循环的结束条件是n2==NULL。当n2是最后一个节点的地址时,n3是为空的。迭代部分将n3赋值给n2,此时再进行n3=n3->next显然是不合适的。

解决:

        if(n3)
        n3=n3->next;
;