【打卡】——【LeetCode学习计划】《数据结构入门-C++》第7天 链表

原文链接:【LeetCode学习计划】《数据结构入门-C++》第7天 链表_Wang_Xin_Ling的博客-CSDN博客

目录

141. 环形链表LeetCode: 141. 环形链表

分析:

方法一:哈希表 

方法二: 快慢指针

21. 合并两个有序链表LeetCode

 方法:递归

方法1优化就如同我们在【LeetCode学习计划】《算法-入门-C++》第8天 广度优先搜索 / 深度优先搜索中提到的问题一样,新链表的所有结点都是l1和l2的结点,如果l1或l2被释放了,那么整个新链表也被破坏了。因此我们新建每一个结点。

方法2:迭代

206. 反转链表LeetCode

方法1:迭代 / 双指针


141. 环形链表
LeetCode: 141. 环形链表

题目:

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。

 

分析:

题目分析:1.pos不可以做为参数的意思是,不能用它来判断

2.题目要我们判断是否有环,我们可以用1)哈希表逐一遍历,如果有环状就会重复,这样就判断有环

2)我们可以用龟兔赛跑算法参考: Floyd判圈算法(龟兔赛跑算法)记录_y4ung-CSDN博客_龟兔算法

题目给好的,创建键值对 (因为链表没有键的概念)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */ 

方法一:哈希表 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        unordered_set<ListNode *> set;

        ListNode *p = head;
        while(p)
        {
            if (set.find(p) == set.end())
            {
                set.insert(p);
            }
            else
                return true;
            p = p -> next;
        }
        return false;
        
    }
};

ListNode* phead=head;

相当于中间储存东西的地方

//不破坏头指针

 

if (set.find(p) == set.end())
            {
                set.insert(p);
            }

如果set中找不到该元素,则增加到set中

else

就是找到了,之前出现过一次,现在又出现一次,证明有环

方法二: 快慢指针

本方法叫做「Floyd 判圈算法」(又称龟兔赛跑算法)

一般来说,我们做题的思路可能是往更少的方向去想,比如更少的遍历次数。而方法2不一样,方法2基于这个事实:进入环之后,就会一直在环中循环。

假设「乌龟」和「兔子」在链表上移动,「乌龟」每次移动一步,「兔子」每次移动两步。如果链表中没有环,那么「兔子」就会一直处于「乌龟」的前方直至链表尾部;如果链表中有环,那么兔子在某个时刻就会到达「乌龟」的后方,我们就是运用这个思路。

但是我们没有办法判断链表中谁在谁的哪里,不过,由于进入环之后将永远处于环中,那么在某个时刻,走一步的「乌龟」和走两步的「兔子」必然会在同一结点相遇,于是我们只要一直进行循环直至两者相遇即可。这也是我们一开始讲的,方法2的思路不像平时那种追求“更少的遍历次数”。
 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head || !head -> next)
            return false;
        ListNode *fast = head, *slow = head;
        do
        {
            if(!fast -> next || !fast ->next->next)
                return false;
            fast = fast->next->next;
            slow = slow->next;
        }while(fast != slow);

    return true;
        
    }
};

 先判断是否有2个元素 以及是否满足快慢指针存在条件

 do while写法,先进行do后判断

21. 合并两个有序链表
LeetCode

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

 方法:递归

 如果l1->val  <  l2->val,那么当前要加入的结点便是l1。我们将l1->next和l2传入递归函数,再将返回值赋给 l1->next
如果l1->val > l2->val,同理

由于上述过程中,l1和l2会一直往后移动,因此当中会有一个先为空。假设当前l1==nullptr,那么我们直接将l2连上即可:return l2
 

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (!l1)
            return l2;
        else if(!l2)
            return l1;
        else if (l1 -> val < l2 -> val)
        {
            l1 -> next = mergeTwoLists(l1->next,l2);
            return l1;
        }
        else
        {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

方法1优化
就如同我们在【LeetCode学习计划】《算法-入门-C++》第8天 广度优先搜索 / 深度优先搜索中提到的问题一样,新链表的所有结点都是l1和l2的结点,如果l1或l2被释放了,那么整个新链表也被破坏了。因此我们新建每一个结点。

新建两个链表中的每一个结点,最后必然会将两个链表全都遍历完,所以最后会出现传入的两个参数都为空指针的情况,这时候我们要单独判断并返回空指针。

class Solution
{
public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        if (!l1 && !l2)
            return nullptr;
        else if (!l1)
            return new ListNode(l2->val, mergeTwoLists(nullptr, l2->next));
        else if (!l2)
            return new ListNode(l1->val, mergeTwoLists(l1->next, nullptr));
        else if (l1->val < l2->val)
            return new ListNode(l1->val, mergeTwoLists(l1->next, l2));
        else
            return new ListNode(l2->val, mergeTwoLists(l1, l2->next));
    }
};

方法2:迭代


我们可以使用循环语句来完成。设p1和p2分别指向l1和l2。当p1和p2皆不为空时,比较各结点的值,选取符合条件的结点连上。有一个为空时就跳出循环,然后单独循环p1和p2,其中必然有一个没有遍历完,将它遍历完即可。

注:以下代码新建了每一个结点。可以选择不新建结点

class Solution
{
public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        if (!l1 && !l2)
            return nullptr;

        ListNode *dummy = new ListNode(-1), *p = dummy;
        ListNode *p1 = l1, *p2 = l2;

        while (p1 && p2)
        {
            if (p1->val < p2->val)
            {
                p->next = new ListNode(p1->val);
                p1 = p1->next;
            }
            else
            {
                p->next = new ListNode(p2->val);
                p2 = p2->next;
            }
            p = p->next;
        }

        while (p1)
        {
            p->next = new ListNode(p1->val);
            p1 = p1->next;
            p = p->next;
        }
        while (p2)
        {
            p->next = new ListNode(p2->val);
            p2 = p2->next;
            p = p->next;
        }

        p = dummy->next;
        delete dummy;
        return p;
    }
};

206. 反转链表
LeetCode

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

方法1:迭代 / 双指针


假设存在链表 1 → 2 → 3 → ∅ 1 \我们想要把它改成 ∅ ← 1 ← 2 ← 3 \ \

3∅←1←2←3。

我们在改变当前指针时,需要把它的next指针指向上一个元素,所以我们需要一个额外的指针prev来指向当前指针的上一个元素。由于要往后访问,又要改当前元素的next,所以我们要有一个next变量预存当前的next。

力扣上老哥的视频

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *prev = nullptr, *p = head;
        while(p)
        {
            ListNode *next = p->next;
            p->next = prev;
            prev = p;
            p = next;
        }

        return prev;

    }
};

 

Guess you like

Origin blog.csdn.net/qq_62932195/article/details/121924437