【单链表经典习题讲解】(一)

简介: 【单链表经典习题讲解】(一)

大家好呀,今天向大家分享的是关于单链表的一些比较基础且经典的题目,相信你看完了一定会对单链表的知识掌握的更加熟练。

1 移除链表元素

题目描述:

3faf08e7c1774f8a9c6e5512fa5e5301.png 解题思路:

遍历链表,用cur表示当前位置,记录要去除元素的前一位地址(prev),让prev->next=cur->next.然后不断迭代,直至cur为空.

但是要额外处理当第一个元素就是要去除元素这种情况。

具体代码实现:

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

结果展示:


75594522d02f49b48770b50f5b15a771.png

2 反转链表

题目描述:

009a4b42159f4c3ba17a56a050f5daf2.png

解题思路1:

遍历链表,让cur指向当前位置,记录cur前一位的位置prev,记录cur后一位位置next,让cur->next=prev,将prev=cur,cur=next,next=next->next,然后不断迭代,结束条件是cur为NULL,但是要注意当next为NULL时就不要进行next=next->next。

789e8cdd2f444458838541f3dafbc98f.png

具体代码:

 ListNode* reverseList(struct ListNode* head)
{
    if(head==NULL)
    {
        return head;
    }
struct ListNode* prev=NULL;
struct ListNode* cur=head;
struct ListNode* next=head->next;
while(cur)
{
    //翻转
    cur->next=prev;
    prev=cur;
    cur=next;
    if(next)
    {
        next=next->next;
    }
}
return prev;
}

结果展示:


7bf692c311404d3695f76f67e79398bb.png

解题思路2:

遍历链表,将链表中的元素头插到一个新链表的头上,然后迭代下去,直到cur为NULL,但是要注意保存cur的下一个位置。

具体代码:

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;
}

结果展示:

f63813352cb54a0bafd45f25ff7791e9.png

两种方法都是可行的,具体用哪一种可以自己选择,但是不要刻意去关注leetcode结果展示中的执行用时和内存消耗,这可能与网速有关。


3 链表的中间结点

题目描述:

435500df58ec496d9aae0184b785630f.png

解题思路:

常规思路:遍历链表求链表长度,然后再遍历一遍数组求中间结点

具体代码:

struct ListNode* middleNode(struct ListNode* head)
{
int count=0;
struct ListNode* cur=head;
while(cur)
{
    count++;
    cur=cur->next;
}
 cur=head;
 int i=0;
 for(i=0;i<count/2;i++)
 {
     cur=cur->next;
 }
return cur;
}

这种方法可行,但是有没有其他方法只遍历一遍链表呢?

快慢指针:让slow一次走一步,fast一次走两步,直到fast或者fast->next为NULL时结束,此时slow就是中间结点。

具体代码:

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

结果展示:


2b180bbac0164352ab497a2f1ed98441.png

4 链表中倒数第k个结点

 

题目描述:

deabb4e1c2de483cbdb8ec770c630ac6.png

解题思路:

仍然用快慢指针解题,让快指针先走k步,然后同时走。

具体代码:

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

其中值得注意的是当fast先走时并且当fast为空时直接返回NULL。

结果展示:

0b31656343f54542a55b20f909f88bd1.png

5 合并两个有序链表

题目描述:dd464e065c5e4bc7ac256c8f1188fd9a.png

解题思路1:

不创建头结点,一 一遍历两个链表,将较小的值拿下来尾插,然后迭代下去,直至其中一个链表为空,然后把另外一个链表剩下的结点全部链接。但是要注意考虑头为NULL的特殊情况

具体代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
struct ListNode* head=NULL;
struct ListNode* tail=NULL;
if(list1==NULL)
{
    return list2;
}
if(list2==NULL)
{
    return list1;
}
while(list1 && list2)
{
    if(list1->val < list2->val)
    {
       if(head==NULL)
       {
           tail=head=list1;
       }
       else
       {
            tail->next=list1;
            tail=tail->next;
       }
       list1=list1->next;
    }
    else
    {
       if(head==NULL)
       {
           tail=head=list2;
       }
       else
       {
            tail->next=list2;
            tail=tail->next;
       }
       list2=list2->next;
    }
}
    if(list1)
    {
        tail->next=list1;
    }
    if(list2)
    {
        tail->next=list2;
    }
    return head;
}

结果展示:


0bdb1be678f241d8832533ca1c3b9977.png

解题思路2:

创建一个头结点,不存储数据,方法与第一种类似,但是不需要考虑头为NULL的情况。

具体代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
if(list1==NULL)
{
    return list2;
}
if(list2==NULL)
{
    return list1;
}
struct ListNode* head=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* tail=head;
while(list1 && list2)
{
    if(list1->val < list2->val)
    {
       tail->next=list1;
       tail=tail->next;
       list1=list1->next;
    }
    else
    {
       tail->next=list2;
       tail=tail->next;
       list2=list2->next;
    }
}
    if(list1)
    {
        tail->next=list1;
    }
    if(list2)
    {
        tail->next=list2;
    }
    struct ListNode* first=head->next;
    free(head);
    return first;
}

结果展示:

a682a31fc44f4accbc1419d467866ff9.png


6 链表分割

题目描述:

d52f2d30b26b4ae6bef4b4fd7e5ebe17.png

解题思路:

创建两个头结点分别连接<x和>=x的链表,最后将较小链表的尾连接到大链表的头的下一位,最后别忘了给大链表的尾置NULL。


848e4d452f114bc69d5b8caf6eef8dc9.png

具体代码:

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        ListNode*headSmall=(ListNode*)malloc(sizeof(ListNode));
        ListNode*tailSmall=headSmall;
        ListNode*headBig=(ListNode*)malloc(sizeof(ListNode));
        ListNode*tailBig=headBig;
        ListNode*cur=pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                tailSmall->next=cur;
                tailSmall=cur;
            }
            else
            {
                tailBig->next=cur;
                tailBig=cur;
            }
            cur=cur->next;
        }
        tailSmall->next=headBig->next;
        tailBig->next=NULL;
        return headSmall->next;
    }
};

结果展示:


cce15d7099d345dfb46fe44142122656.png




目录
相关文章
|
6月前
|
存储 测试技术 C++
二叉树——经典练习题
二叉树——经典练习题
|
5月前
|
机器学习/深度学习 算法 C语言
【C/数据结构与算法】:10道链表经典OJ
【C/数据结构与算法】:10道链表经典OJ
22 1
|
6月前
|
存储 测试技术 计算机视觉
栈和队列经典练习题
栈和队列经典练习题
|
5月前
|
算法 C语言
【数据结构与算法 经典例题】链表的回文结构(图文详解)
【数据结构与算法 经典例题】链表的回文结构(图文详解)
|
6月前
详解单链表经典OJ题-1
详解单链表经典OJ题
28 2
|
6月前
|
算法
详解单链表经典OJ题-2
详解单链表经典OJ题
34 2
|
6月前
|
算法 索引
链表经典练习题
链表经典练习题
|
6月前
|
索引
单链表经典OJ题(四)
单链表经典OJ题(四)
|
6月前
单链表经典OJ题(二)
单链表经典OJ题(二)
|
6月前
|
索引
单链表经典OJ题(三)
单链表经典OJ题(三)