图灵日记之Leetcode链表中间结点&&牛客链表中倒数第k个结点&&Leetcode合并两个有序链表&&leetcode反转链表

题目

  • 链表的中间结点
    • 原题入口
    • 题目内容
    • 题目解析
      • 思路一
      • 代码实现一
      • 思路二
      • 代码实现二
  • 链表中倒数第k个结点
    • 题目链接
    • 题目内容
    • 思路
    • 代码实现
  • 合并两个有序链表
    • 原题入口
    • 题目内容
    • 思路
    • 代码实现
  • 反转链表
    • 题目传送入口
    • 题目内容
    • 思路一
    • 代码复现一
    • 思路二
    • 代码实现二

链表的中间结点

原题入口

题目内容

给你单链表的头结点 head ,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

题目解析

该题我们选择一次遍历返回中间结点,可以选择两次遍历,只是时间复杂度变大了,这里介绍比较优的解法

思路一

该思路利用快慢指针的方法,快指针一次跳两个结点,慢指针一次跳一个结点,来实现中间的效果,此处中间的思想有了头绪,那么结束循环的条件又是我们要考虑的了,如果是奇数个结点,fast在最后一个结点停止,最后一个结点的next才等于NULL,奇数的结束条件是fast->next==NULL;就偶数而言,结束条件就是NULL

代码实现一

struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* fast=head,* slow=head;
    //可以简化代码,把slow去除,直接替换为head
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

思路二

核心思想是使用两个计数器 count 和 ret,通过遍历链表找到中间位置的节点。其中,通过判断 count / 2 + 1 > ret 来确定是否为中间位置。这样,当循环结束时,head 指向的节点即为链表的中间节点。

代码实现二

struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* tem = head;
    int count = 1,ret = 1;
    while(tem)
    {        
        if(count/2+1>ret)
        {
            head=head->next;
            ret++;
        }
        count++;        
        tem=tem->next;
    }
    return head;
}

链表中倒数第k个结点

题目链接

题目内容

输入一个链表,输出该链表中倒数第k个结点。

思路

快慢指针的思想,先让快指针走k步,然后快慢指针同时走,注意判断快指针是否越界

代码实现

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) 
{
    struct ListNode* p1=pListHead,* p2=pListHead;
    while(k--)
    {
        if(p1==NULL) return NULL;
        p1=p1->next;
    }
    while(p1)
    {
        p2=p2->next;
        p1=p1->next;
    }
    return p2;
}

合并两个有序链表

原题入口

题目内容

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

思路

类似两个有序数组合并,先考虑空链表的情况,再通过遍历两个有序链表一次,逐个比较节点的值,将较小的节点连接到合并链表中,最终得到合并后的有序链表。

代码实现

struct ListNode* mergeTwoLists(struct ListNode* list1, struct  ListNode* list2) 
{
    struct ListNode* head = NULL,* tail = NULL;
    if(list1==NULL) return list2;
    if(list2==NULL) return list1;
    while(list1&&list2)
    {
        if(list1->val>list2->val)
        {
            if(head==NULL)
            {
                head=tail=list2;
            }
            else
            {
                tail->next=list2;
                tail=tail->next;
            }
            list2=list2->next;

        }
        else 
        {
           if(head==NULL)
            {
                head=tail=list1;
            }
            else
            {
                tail->next=list1;
                tail=tail->next;
            }   
            list1=list1->next;
        }
    }
    if(list1)
    tail->next=list1;
    if(list2)
    tail->next=list2;
    return head;
}

反转链表

题目传送入口

题目内容

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

思路一

在遍历链表的过程中,改变结点指向的方向,原题实例,如果将2的next指向1的话,你就丢失2之后的结点,所以我们要用3个指针**,前两个指针改变导向,第三个指针记录第二个指针的下一个位置**

代码复现一

struct ListNode* reverseList(struct ListNode* head) 
{    
    if(head==NULL) return NULL;
    struct ListNode* p1 = NULL;
    struct ListNode* p2 = head;
    struct ListNode* p3 = head->next;
    while(p2)
    {
        p2->next = p1;
        p1=p2;
        p2=p3;
        if(p3)
        p3=p3->next;
    }
    return p1;
}

思路二

第二种思路与第一种比较相似,第二种采用尾插的方法来进行结点的逐个插入,仍旧采用三指针,前两个指针对结点尾插,第三个结点记录下一个结点的位置,防止失去与原链表的关联

代码实现二

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

你可能感兴趣的:(leetcode,链表,算法)