【数据结构】简单链表OJ

目录

[leetcode] 203.移除链表元素

[leetcode]206.反转链表

[leetcode]876.链表的中间结点

[牛客]链表中倒数第k个结点

总结


[leetcode] 203.移除链表元素

 

 首先分析思路:

第一种思路是用一前一后两个指针同时往后走,为什么呢,因为你删除某个结点需要前一个结点找到它的下一个结点,这就意味着,你需要找到要去除的这个结点的前一个结点,所以需要两个相邻的指针同时向后走,当前一个指针cur走到要删除的结点时,让prev指针先指向cur的next,然后再让cur指向prev的next,继续往后走,直到cur为NULL。

ok,根据这个思路我们写一下代码:

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

接下就需要我们分析一下特殊情况,看上述代码是否可以满足:

1.如果val都为x,要删除的val也是x呢?也就是最后会删空呢?

我们发现代码走到else的第一句就出问题了,因为此时prev还是空指针,没有next,相当于头删

 所以我们需要对这种情况单独处理:

 ok,这样这个题就解决了

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

 那么还有第二种思路是:把不是val的值,尾插到新链表

定义一个头指针newhead用于最后返回新链表的头,再定义一个尾指针tail时刻指向新链表的尾:

struct ListNode* removeElements(struct ListNode* head, int val){
        struct ListNode* newhead = NULL,*tail = NULL;
        struct ListNode* cur=head;
        while(cur)
        {
            if(cur->val!=val)
            {
                //尾插
                if(tail==NULL)
                {
                    newhead=tail=cur;
                }
                else 
                {
                    tail->next=cur;
                    tail=tail->next;
                }
                cur=cur->next;

            }
            else
            {
                struct ListNode* next=cur->next;
                free(cur);
                cur=next;
            }
        }
        if(tail)
            tail->next=NULL;
        return newhead;
      
}

[leetcode]206.反转链表

首先分析思路:

首先我们考虑能不能让这个链表反转过来,下一个结点指向上一个结点,那么怎么实现呢?用一个双指针,一前一后,走在前面的指针指向后边的指针,,但我们容易发现这样的话,前面的指针就不再指向原来的下一个结点了,导致我们找不到下一个结点,那么怎么办呢,我们再用第三个指针指向下一个结点就好了,那么这道题就转换成了三指针问题。

 如图,当n2为NULL时结束

struct ListNode* reverseList(struct ListNode* head){
           if(head==NULL)
               return NULL;
           struct ListNode* n1,*n2,*n3;
           n1=NULL;
           n2=head;
           n3=n2->next;
           while(n2)
           {
               n2->next=n1;
               n1=n2;
               n2=n3;
               if(n3)
               n3=n3->next;
           }
           return n1;
}

由图可知,结束时要对n3进行非空判断,同时也需要对空链表进行特殊处理。 

还有一种思路是取原结点头插到新链表,我们需要先保存下一个结点,然后把当前结点头插到新链表中,然后对下一个结点进行同样的操作,直到全部头插完,返回新链表的头。

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* cur = head,*newhead=NULL;
    while(cur)
    {
         struct ListNode*next=cur->next;
         cur->next=newhead;
         newhead=cur;
         cur=next;
    }
    return newhead;

}

[leetcode]876.链表的中间结点

首先分析一下思路:

这里给出一种常用的方法:快慢指针(slow/fast),这个方法适用于很多题 ,什么意思呢,我们让两个指针从头同时开始走,slow指针一次走一个,fast指针一次走两个,这样当fast走到尾时,slow的位置就是中间结点。

这里需要考虑的时奇数偶数问题,奇数时fast走到尾;偶数时fast走到NULL

ok,我们代码实现一下:

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

     return slow;
}

这道题很简单,这里我们主要是引出快慢指针的方法,后面还会用到这种方法哟~ 

[牛客]链表中倒数第k个结点

 ok我们还是先分析思路:首先它要求输出倒数第k个结点,那么我们很容易想到的思路是可以先求出链表的长度n,然后输出第n-k个结点就可以了;但是嘞,我想说的是我们上一道题说的快慢指针的方法,只是这里的快慢指针的快慢体现在距离上,我们可以先让快指针走k步,然后和慢指针同时走,当快指针走到NULL时,慢指针的位置就是要找的倒数第k个结点。

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    if(pListHead==NULL)
        return NULL;
    struct ListNode*slow,*fast;
    slow=fast=pListHead;
    while(k--)
    {
        if(fast==NULL)
            return NULL;
        fast=fast->next;
        
    }
    while(fast)
    {
        slow=slow->next;
        fast=fast->next;
    }
    return slow;
}

总结

这篇文章只是挑选了一部分简单的经典链表oj题,难度不大,重点在于感受其中的思路,我们尤其注意在很多题中都有出现需要特殊处理的情况,这就要求我们思维全面,对链表足够熟悉 ,ok下一篇文章依然是一些链表oj题,但是难度是呈不断上升趋势,所以,感兴趣的老铁点个关注,我们下一篇再见~

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值