写点什么

每日算法刷题 Day14- 反转链表、两个链表的第一个公共结点、删除链表中重复的节点

作者:timerring
  • 2022 年 9 月 20 日
    山东
  • 本文字数:1799 字

    阅读完需:约 6 分钟

⭐每日算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,与笔者另一系列文章有所区别,并不是以知识点的形式提升算法能力,而是以实战习题的形式理解算法,使用算法。

🔥本文已收录于算法刷题系列专栏: 每日算法题解 欢迎订阅,持续更新。



42.反转链表

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。


思考题:


  • 请同时实现迭代版本和递归版本。

数据范围

链表长度 [0,30]。

样例

输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
复制代码

思路

反转链表是一个经典题目


  • 这里先判断头节点是否为空,或者仅存在一个节点,返回即可。

  • 在分别定义头节点和下一个节点

  • 采用移位的方式依次连接

  • 先存储 q 节点的指向

  • 再让 q 节点指向前节点 p

  • 然后移动 q 节点到其下一个节点处

  • 最后移动 p 节点到 q 节点处即可,保证其先后顺序

  • 最后将其头节点指向空即可

  • 返回 p 节点(原 q 节点已经指向空了)


/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public:    ListNode* reverseList(ListNode* head) {        if(!head || !head -> next)return head;                auto p = head, q = p -> next;                while(q)        {            auto o = q -> next;            q -> next = p;            p = q;            q = o;        }        head -> next = NULL;        return p;    }};
复制代码

43.两个链表的第一个公共结点

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


当不存在公共节点时,返回空节点。

数据范围

链表长度 [1,2000]。

样例

给出两个链表如下所示:A:        a1 → a2                     c1 → c2 → c3B:     b1 → b2 → b3
输出第一个公共节点c1
复制代码

空节点的三种写法

  • 0

  • NULL

  • nullptr

思路


首先分别设 headA 为 p,headB 为 q,然后依次同时移动它们,节点遍历到尽头后,跳转到另一个头节点。


如果最后遍历相同的步数,二者相等,则该节点就为两链表的第一个公共节点。


prove:假设 p 前半部分长度为 a,q 前半部分长度为 b,公共部分为 c。节点 p 遍历总长度为 a+c+b,节点 q 遍历总长度为 b+c+a,二者相等。


/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public:    ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {        auto p = headA;        auto q = headB;        while(p != q)        {            if(p) p = p -> next;            else p = headB;            if(q) q = q -> next;            else q = headA;                }        return p;    }};
复制代码

44.删除链表中重复的节点

在一个排序的链表中,存在重复的节点,请删除该链表中重复的节点,重复的节点不保留。

数据范围

链表中节点 val 值取值范围 [0,100]。


链表长度 [0,100]。

样例 1

输入:1->2->3->3->4->4->5
输出:1->2->5
复制代码

样例 2

输入:1->1->1->2->3
输出:2->3
复制代码

思路


由于存在头节点重复的可能性,因此需要定义一个虚拟节点指向头节点。


循环条件为 p->next 是否存在


  • 定义 q = p -> next;

  • 若 q 节点不是尾节点且 p 的指向与 q 的指向相同,即重复,跳过该节点。

  • 判断 p 的指向是否是 q,如果是移动到 q 位置,否代表有重复跳过了,同时舍弃重复的 q 节点,指向 q 的下一个节点即可。此时再次循环时会更新 q 为 p 的下一个节点。


图解如上:


/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public:    ListNode* deleteDuplication(ListNode* head) {        auto dummy = new ListNode(-1);        dummy -> next = head;        auto p = dummy;                while(p -> next)        {            auto q = p -> next;            while(q -> next && p -> next -> val == q -> next -> val)q = q -> next;                        if(q == p ->next)p = q;            else p -> next = q -> next;        }        return dummy -> next;            }};
复制代码


发布于: 刚刚阅读数: 4
用户头像

timerring

关注

还未添加个人签名 2022.07.14 加入

还未添加个人简介

评论

发布
暂无评论
每日算法刷题Day14-反转链表、两个链表的第一个公共结点、删除链表中重复的节点_算法题_timerring_InfoQ写作社区