【数据结构与算法】:10道链表经典OJ

这篇具有很好参考价值的文章主要介绍了【数据结构与算法】:10道链表经典OJ。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 移除链表元素

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法
思路1:遍历原链表,将 val 所在的节点释放掉。(太麻烦)

思路2:创建新链表,再遍历原链表,找到不为 val 的节点尾插到新链表。

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路1代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.当尾插上最后一个有效节点时,此时它的 next 可能还与最后一个节点相链接,一定要断开!


typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
    if (head == NULL)
        return NULL;

    //创建一个新链表
    ListNode* newHead, * newTail;
    newHead = newTail = NULL;
    ListNode* pcur = head;

    //遍历原链表,找不为val的节点尾插
    while (pcur)
    {
        ListNode* next = pcur->next;
        if (pcur->val != val)
        {
            //没有一个节点
            if (newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            else
            {
                //有一个节点以上
                newTail->next = pcur;
                newTail = newTail->next;
            }
        }

        pcur = next;
    }

    if (newTail)
        newTail->next = NULL;

    return newHead;

}

2. 反转链表

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

2.1反转指针法

思路:定义三个变量 n1,n2,n3,根据它们的指向关系进行迭代。
【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.在迭代过程中别忘记判断 n3 ,防止对空指针解引用。
3.注意循环结束的条件,当 n2 为空时,n1 指向反转后的头,此时循环结束。

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {

    if (head == NULL)
        return NULL;

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

2.2 头插法

思路:创建一个新链表,遍历原链表,依次取下原链表的每一个节点头插到新链表中。

代码实现如下:

注意:
1.当链表为空时,直接返回NULL即可。
2.头插时可以不用判断没有节点和有节点的情况。


typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {

    if (head == NULL)
        return NULL;

    ListNode* newHead, * newTail;
    newHead = newTail = NULL;
    ListNode* pcur = head;

    //一个一个拿下来头插
    while (pcur)
    {
        ListNode* next = pcur->next;
        pcur->next = newHead;
        newHead = pcur;
        pcur = next;

    }

    return newHead;
}

3. 合并两个有序链表

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路:创建一个带哨兵位的新链表,遍历两个原链表,比较两个节点的值,哪个小就先尾插到新链表中。

代码实现如下:

注意:
1.当其中一个链表为空时,返回另一个链表即可。
2.创建哨兵位节点,方便尾插。
3.注意循环结束条件,当其中有一个链表走完时,跳出循环。
4.剩下的没走完的那个链表直接链接到后面。不需要用循环链接,因为它们本来就是连在一起的。
5.别忘记释放释放哨兵位节点,释放前要保存下一个节点。


typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {

    ListNode* n1, * n2;
    n1 = list1;
    n2 = list2;

    if (n1 == NULL)
        return n2;
    if (n2 == NULL)
        return n1;

    //创建哨兵位节点
    ListNode* phead = (ListNode*)malloc(sizeof(ListNode));
    ListNode* newHead, * newTail;
    newHead = newTail = phead;

    while (n1 && n2)
    {
        //比较两个链表中数据的大小,谁小就先尾插到新链表
        if (n1->val < n2->val)
        {
            newTail->next = n1;
            n1 = n1->next;
            newTail = newTail->next;
        }
        else
        {
            newTail->next = n2;
            n2 = n2->next;
            newTail = newTail->next;
        }
    }

    if (n1)
        newTail->next = n1;
    if (n2)
        newTail->next = n2;

    ListNode* ret = newHead->next;
    free(newHead);

    return ret;

}

4. 分隔链表

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路:创建两个带哨兵位的新链表 less 和 greater 。遍历原链表,把小于x 的节点尾插到 less 链表中,把大于等于x 的节点尾插到greater 链表中。最后把 less 链表中的尾结点的 next 链接到 greater链表中的头结点上。

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

代码实现如下:

注意:
1.当链表尾空时,直接返回NULL即可。

2.有可能存在greater 链表中的最后一个结点与原链表中的最后一个结点仍然相链接的情况,一定要断开!


typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x) {
    if (head == NULL)
        return NULL;

    ListNode* lessHead, * lessTail, * greaterHead, * greaterTail;
    ListNode* pcur = head;

    //创建哨兵位节点,方便尾插
    lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
    greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));
    lessTail->next = NULL;
    greaterTail->next = NULL;

    while (pcur)
    {
        if (pcur->val < x)
        {
            lessTail->next = pcur;
            lessTail = lessTail->next;
        }
        else
        {
            greaterTail->next = pcur;
            greaterTail = greaterTail->next;
        }

        pcur = pcur->next;
    }

    lessTail->next = greaterHead->next;
    greaterTail->next = NULL;

    return lessHead->next;

}

5. 环形链表

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

这是一个非常经典的例题,它要用上一种非常经典的算法:快慢指针法

定义一个 slow 变量,fast 变量,从链表的头结点开始,slow 每次走一步,fast 每次走两步,当 slow 进入环中时,fast 开始追逐。若成环,则必会在环内的某处相遇,否则 fast 或是 fast->next 最后会走到NULL。

代码实现如下:

注意:
1.当链表节点个数为偶数个时,若不成环,最终 fast == NULL。
当链表节点个数为奇数个时,若不成环,最终 fast->next == NULL.

2.循环条件 fast && fast->next 的位置不能交换。因为当为偶数个节点,fast走到NULL时,如果是 fast->next && fast ,那就是先执行 fast->next ,对空指针解引用,错误!!


typedef struct ListNode ListNode;
bool hasCycle(struct ListNode* head) {

    ListNode* slow, * fast;
    slow = fast = head;

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)
            return true;
    }

    return false;
}

6. 链表的中间节点

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

也要用快慢指针法。也要分两种情况:
【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

代码实现如下:

注意:
循环条件 fast && fast->next 的位置不能交换。因为当为偶数个节点,fast走到NULL时,如果是 fast->next && fast ,那就是先执行 fast->next ,对空指针解引用,错误!!


typedef struct ListNode ListNode;

struct ListNode* middleNode(struct ListNode* head) {
    ListNode* slow = head;
    ListNode* fast = head;

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }

    return slow;

}

7. 链表中倒数第K个节点

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路:
(1) fast 先走 k 步;
(2) slow 和 fast 再一起走,当 fast == NULL 时,slow 就是倒数第 k 个节点。

代码实现如下:

注意:
当 k 大于链表长度时,fast 会走到 NULL ,不能对空指针解引用,直接返回 NULL。


typedef struct ListNode ListNode;
struct ListNode* FindKthToTail(struct ListNode* pHead, int k ) {
    ListNode* fast ,*slow;
    fast = slow = pHead;
 
    //fast先走K步
    while(k--)
    {
        //K大于链表长度时,直接返回NULL
        if(fast == NULL)
        {
            return NULL;
        }
         
        fast = fast->next;
    }
 
    //再两者一起走
    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
 
    return slow;
    
 }

8. 相交链表

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法
首先要明确什么是相交链表:
【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路1:暴力求解,时间复杂度O(N*N)
依次取A链表中的每个节点跟B链表中的所有节点比较。如果有相同地址的节点,则相交,第一次相同地址的节点就是交点,否则就不相交。

思路2:时间复杂度O(N)
(1) 先找到两个链表的尾,同时计算出两个链表的长度;
(2) 求出长度差;
(3) 判断哪个是长链表;
(4) 让长链表先走长度差步;
(5) 最后长短链表一起走,直到找到交点。

思路2代码实现如下:

注意:
要注意步骤(3)中判断长短链表的巧妙方法。可以避免写重复代码。

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    
    ListNode* TailA,*TailB;
    TailA = headA;
    TailB = headB;

    //找尾同时计算长度
    int lenA = 0;
    int lenB = 0;
    while(TailA->next)
    {
        TailA = TailA->next;
        lenA++;
    }

     while(TailB->next)
    {
        TailB = TailB->next;
        lenB++;
    }

    //不相交
    if(TailA != TailB)
    {
        return NULL;
    }

    //求出长度差
    int gap = abs(lenA - lenB);

    //判断哪个是长链表
    ListNode* longList = headA;//先默认A是长链表
    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;

}

9. 环形链表的约瑟夫问题

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路:
首先要创建一个循环链表,定义一个计数器 count 用于数数,再遍历循环链表,当结点的 val == count 时,就"杀死",即销毁该节点。

代码实现如下:

注意:
要学习创建循环链表的方法!


 typedef struct ListNode ListNode;
   
  //创建节点
  ListNode* BuyNode(int x)
  {
    ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
    if(newnode == NULL)
    {
        exit(-1);
    }
 
    newnode->val = x;
    newnode->next = NULL;
 
    return newnode;
  }
 
 //1.创建循环链表
 ListNode* Createnodecircle(int n)
 {
    ListNode* phead = BuyNode(1);
    ListNode* ptail = phead;
    for(int i=2;i<=n;i++)
    {
        ptail->next = BuyNode(i);
        ptail = ptail->next;
    }
    //尾连头,成环
    ptail->next = phead;
 
    return ptail;
 
 }
 
int ysf(int n, int m ) {
   
     ListNode* prev = Createnodecircle(n);
     ListNode* pcur = prev->next;
     
     //开始数数
     int count = 1;
     while(pcur->next!=prev->next)
     {
         if(count == m)
         {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
         }
         else
         {
         prev = pcur;
         pcur = pcur->next;
         count++;
         }
    }
 
         return pcur->val;
     }

10. 链表的回文结构

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

这个题在牛客网中不能用C语言实现,我们可以选C++,因为C++是兼容C的,在C++中可以使用C的语法。

【数据结构与算法】:10道链表经典OJ,链表,数据结构,c语言,算法

思路:
(1) 找到链表的中间节点;
(2) 把中间节点后面的链表进行逆置;
(3) 最后把逆置后的链表的值与中间节点之前的链表的值进行比较,若所有节点相等,则是回文链表,否则不是。有一个链表结束则比较结束。

代码实现如下:

注意:
逆置完之后,中间节点与前一个结点的链接可以不用断开,因为就算链接在一起也不影响判断。若强行断开,徒增麻烦。文章来源地址https://www.toymoban.com/news/detail-851101.html


//找中间结点
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;
 
}
 
 //对中间结点之后的链表进行逆置
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;
}
  
class PalindromeList {
  public:
    bool chkPalindrome(ListNode* A) {
        
    struct ListNode* mid = middleNode(A);
    struct ListNode* rHead = reverseList(mid);
     
    struct ListNode* curA = A;
    struct ListNode* curR = rHead;
 
    //把逆置后的链表与中间结点之前的链表进行比较
    while(curA && curR)
    {
         if(curA->val != curR->val)
         {
            return false;
         }
         else
         {
            curA = curA->next;
            curR = curR->next;
         }
    }
    return true;
 
    }
 };

到了这里,关于【数据结构与算法】:10道链表经典OJ的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构——链表OJ题

    目录   1.给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 2.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。 3.变形题:找到链表中倒数第k个

    2024年02月21日
    浏览(40)
  • 二叉树经典OJ题——【数据结构】

    W...Y的主页  😊 代码仓库分享 💕  今天我们来进行二叉树的OJ练习,就是利用二叉树的前序、中序、后续以及晨序遍历的特性进行OJ训练。话不多说,来看我们的第一道题。 【leetcode 965.单值二叉树】 OJ链接  如果二叉树每个节点都具有相同的值,那么该二叉树就是 单值 二

    2024年02月07日
    浏览(46)
  • 【数据结构】栈与队列经典oj题

    🚀write in front🚀 📜所属专栏:初阶数据结构 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!! 关注我,关注我,关注我 , 你们将会看到更多的优质内容!!   栈两种线性表示都能实现

    2024年02月03日
    浏览(41)
  • 【数据结构初阶】链表OJ

    OJ 方案一: 题目解析: 方案二: 题目解析:把原链表遍历一遍,插入新链表 OJ 题目解析: OJ 题目解析: OJ 题目解析: OJ 题目解析: OJ 题目解析: OJ 题目解析: OJ 题目解析: 定义快慢指针,使快指针先走与慢指针同步。然后同时走看是否相交 OJ 题目解析: OJ 题目解析:

    2024年02月05日
    浏览(50)
  • 数据结构——图解链表OJ题目

            学完了单链表之后,我们对其基本结构已经有了一定的了解,接下来我们通过一些题目强化对链表的理解,同时学习一些面试笔试题目的新思路以及加强对数据结构单链表的掌握。  目录 题目一.876. 链表的中间结点 - 力扣(LeetCode) 题目二:21. 合并两个有序链表

    2024年02月04日
    浏览(65)
  • 【数据结构OJ题】环形链表

    原题链接:https://leetcode.cn/problems/linked-list-cycle/description/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 整体思路: 定义 快慢指针fast,slow ,如果 链表确实有环 , fast指针一定会在环内追上slow指针。 即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,

    2024年02月12日
    浏览(41)
  • 【数据结构OJ题】链表分割

    原题链接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8tqId=11004rp=2ru=/activity/ojqru=/ta/cracking-the-coding-interview/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 整体思路: 创建两个链表 ,分别存放 小于x的结点 和 大于等于x的结点 , 分别进行尾插 。 这道题目使

    2024年02月12日
    浏览(44)
  • 【数据结构】反转链表、链表的中间节点、链表的回文结构(单链表OJ题)

    正如标题所说,本文会图文详细解析三道单链表OJ题,分别为:  反转链表 (简单)  链表的中间节点 (简单)  链表的回文结构 (较难) 把他们放在一起讲的原因是:  反转链表 和  链表的中间节点 是  链表的回文结构 的基础 为什么这样说?请往下看: 目录 1. 反转链

    2024年02月13日
    浏览(71)
  • 【数据结构OJ题】环形链表II

    原题链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/ 如果有小伙伴不了解环形链表,可以先看看这篇文章: https://blog.csdn.net/m0_62531913/article/details/132352203?spm=1001.2014.3001.5502 我们来看下图:  我们根据这个结论就可以做出这道题目了!

    2024年02月12日
    浏览(43)
  • 【数据结构OJ题】移除链表元素

    原题链接:力扣  给你一个链表的头节点  head  和一个整数  val  ,请你删除链表中所有满足  Node.val == val  的节点,并返回 新的头节点  。  方法一:原地删除节点 思路:  首先,定义两个指针:prve和cur。它们会在遍历链表的过程中分别指向当前节点的前一个节点和当前

    2024年02月11日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包