【leetcode题解】——链表OJ题

文章目录

  • 前言
  • 一、21. 合并两个有序链表
  • 二、876. 链表的中间结点
  • 三、206. 反转链表
  • 四、 141. 环形链表
  • 五、142. 环形链表 II


前言

学习数据结构ing……
【leetcode题解】——链表OJ题_第1张图片


`

一、21. 合并两个有序链表

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

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:

输入:l1 = [], l2 = []
输出:[]
示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

思路一:先去一个头

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL)
    {
        return l2;
    }
    if(l2==NULL)
    {
        return l1;
    }
    struct ListNode* head=NULL;
    struct ListNode* tail=NULL;
    if(l1->val>l2->val)
    {
        head=tail=l2;
        l2=l2->next;
     
        // l1=l1->next;
    }
    else
    {
        head=tail=l1;
        l1=l1->next;
  
        //l2=l2->next;
    }
    while(l1!=NULL&&l2!=NULL)
    {
        if(l1->val>l2->val)
        {
            tail->next=l2;
            l2=l2->next;
        }
        else
        {
            tail->next=l1;
            l1=l1->next;
        }
        tail=tail->next;
    }
    if(l1)
    {
         tail->next=l1;
    }
    if(l2)
    {
        tail->next=l2;
    }
    return head;
}

二、876. 链表的中间结点

给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。
(测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4,
ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

思路:快慢指针

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

三、206. 反转链表

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

示例 1:

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

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

输入:head = [] 输出:[]

思路一:反转指针的方向

struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL)
    {
        return head;
    }
struct ListNode* n1=NULL;
struct ListNode* n2=head;
struct ListNode* n3=n2->next;
while(n2)
{
    n2->next=n1;
    
    n1=n2;
    n2=n3;
    if(n3)
    n3=n3->next;

}
return n1;
}

思路二:头插法:

struct ListNode* reverseList(struct ListNode* head){
struct ListNode* newnode=NULL;
struct ListNode* cur=head;
while(cur)
{
    struct ListNode* next=cur->next;
    cur->next=newnode;
    newnode=cur;
    cur=next;
}
return newnode;
}

四、 141. 环形链表

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

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

示例 1:

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

输入:head = [1,2], pos = 0 输出:true

解释:链表中有一个环,其尾部连接到第一个节点。 示例 3:

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

题解:

bool hasCycle(struct ListNode *head) {
    struct ListNode *solve=head;
    struct ListNode *fast=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        solve=solve->next;
        if(fast==solve)
        {
            return true;
        }
    }
    return false;
}

小tips: (1)请证明solve每次走一步,fast每次走两步,那么fast和solve一定会相遇吗?
(2)请证明solve每次走一步,fast每次走三步,那么fast和solve一定会相遇吗?
或者solve每次走一步,fast每次走四步,那么fast和solve一定会相遇吗? 结论:
(1)solve每次走一步,fast每次走两步,那么fast一定会追上solve的 (2)当solve每次走一步,fast每次走三步时:
设solve和fast都进环里面来了,设他们之间的距离为N,每次距离缩减2
即N->N-2->N-4->N-6……
若N为偶数那么最后距离为0即可以相遇
若N为奇数,那么最后结果为-1即fast会在solve前面
设这个环的长度为C
那么他们的新距离就为C-1;
同理
若C-1为偶数那么最后距离为0即可以相遇
若C-1为奇数,那么最后结果为-1即fast会在solve前面,此时会陷入死循环,因为每次快相遇的时候都是fast跑solve前面去了。

五、142. 环形链表 II

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

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

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

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

解题思路: 依旧是使用快慢指针,令slow一次移动移位,fast一次移动两位 则总会在圆环里面一点相遇
设从head到圆环入口距离为L,圆环长C,当两指针相遇时距离圆环入口距离为X
当L够短,C够长时时,当fast刚只走了一圈则有C+X+L=2*(L+X)->C-X=L
这只是特例,若L够长时,那么fast可能已经走了n圈了
此时:nC+X+L=2(L+X)->C-X=L->n*C-X=L->(n-1)*C+C-X=L
即若有两个速度为1的指针分别从head走的指针begin和相遇点走的的指针meet,那么当begin走到入口处时,走了L的距离,此时meet从相遇点绕了n-1圈之后,会到了相遇点,再走C-X的距离就也到了入口处,此时刚好相遇。
【leetcode题解】——链表OJ题_第2张图片

    struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow=head;
    struct ListNode *fast=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            struct ListNode *meet=fast;
            struct ListNode *begin=head;
            while(begin!=meet)
            {
               meet=meet->next;
               begin=begin->next;
            }
            return meet;
           
        }
    }
    return NULL;
}

你可能感兴趣的:(C语言——题解,算法,c语言)