Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)

目录

141. 环形链表

问题描述:

实现代码与解析:

快慢指针:

原理思路:

142. 环形链表 II

问题描述:

实现代码与解析:

快慢指针

原理思路:

143. 重排链表

题目描述:

实现代码与解析:

线性表

原理思路:


141. 环形链表

问题描述:

        给你一个链表的头节点 head ,判断链表中是否有环。

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第1张图片

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第2张图片

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

实现代码与解析:

快慢指针:

/**
 * 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) {
        ListNode* slow = head;
        ListNode* fast = head;

        // fast->next 这个条件,防止fast为空结点
        while(slow && fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) return true;
        }
        return false;
    }
};

原理思路:

        慢指针一次走一步,快指针一次走两步,若最后能相遇说明有环。

142. 环形链表 II

问题描述:

        给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

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

不允许修改 链表。

示例 1:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第3张图片

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第4张图片

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

实现代码与解析:

快慢指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) 
    {
        ListNode* fast=head;//快指针
        ListNode* slow=head;//慢指针
        while(fast!=NULL&&fast->next!=NULL)
        {
            slow=slow->next;//慢指针每次走一步
            fast=fast->next->next;//快指针每次走两步
            if(slow==fast)
            {
                ListNode* index1=fast;//记录相遇位置
                ListNode* index2=head;
                //当快慢指针相遇时,两指针从head和相遇点同时出发,直至相遇,找到换的入口
                while(index1!=index2)
                {
                    index1=index1->next;
                    index2=index2->next;
                }
                return index1;
            }
        }
        return NULL;//若无环

    }
};

原理思路:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第5张图片
        slow指针一次走一步,fast指针一次走两步。 

        其中n为fast指针在圈里转的圈数,根据算的结果可以看出,当n=1时,z=x,也就是说fast与slow相遇点到环的入口的长度等于x的长度,所以我们只要在头结点和相遇点定义index1,index2两个指针,一起移动,当其相遇的时候,就移动到了环的入口结点,直接返回即可。当然n不一定等于1,根据最后公式,只不过index2会在环里转几圈,最后还是会与index1在环入口相遇。

        至于fast指针与slow指针为什么一定会相遇,而不是fast指针跳过slow指针呢?因为fast指针相对于slow指针一次是走一步,相当于物理里的相对运动吧,既然是走一步,那必然不会出现跳过的情况。

        至于为什么slow指针不会在环里转超过一圈呢?因为fast指针一次走的是slow指针一次走的两倍,当slow走完一圈时,fast必然会走完两圈,所以在此之前两指针一定会相遇。

143. 重排链表

题目描述:

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第6张图片

输入:head = [1,2,3,4]
输出:[1,4,2,3]

示例 2:

Leetcode每日一题:141. 环形链表、142. 环形链表 II、143. 重排链表(2023.7.29、30、31 C++)_第7张图片

输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]

实现代码与解析:

线性表

/**
 * 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:
    void reorderList(ListNode* head) {

        ListNode* cur = head;
        vector v;

        while(cur)
        {
            v.push_back(cur);
            cur = cur->next;
        }

        int l = 0, r = v.size() - 1;
        while(l < r)
        {
            v[l]->next = v[r];
            l++;
            if (l == r) break;
            v[r]->next = v[l];
            r--;
        }
        v[l]->next = nullptr;
        //重排后的链表,最后一个节点是原来链表中间的节点,其next不为空,我们需要手动将next设为空。
    }
};

原理思路:

        链表不能记录位置,我们用线性表存一下进行操作即可。

你可能感兴趣的:(Leetcode,leetcode,链表,c++)