单链表经典OJ题分析

目录

一、链表的中间节点

1.1 题目

1.2 题解

1.3 收获

二、移除链表元素

2.1 题目

2.2 题解

2.3 收获

2.4递归详解

三、反转链表

3.1 题目

3.2 题解

3.3 解释

四、合并两个有序列表

4.1 题目

4.2 题解

4.3 递归详解


声明:本文所有题目均摘自leetcode

一、链表的中间节点

1.1 题目

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

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

1.2 题解

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

1.3 收获

  • 快慢指针的用法:
  • 链表长度为奇数: 当快指针走到尾节点时,慢指针正好走到中间节点。
  • 链表长度为偶数: 当快指针走到NULL时,慢指针正好走到第二个中间节点。

二、移除链表元素

2.1 题目

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

2.2 题解

//创建虚拟节点法
struct ListNode* removeElements1(struct ListNode* head, int val) {
    struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode* temp = dummyHead;
    while (temp->next != NULL) {
        if (temp->next->val == val) {
            temp->next = temp->next->next;
        }
        else {
            temp = temp->next;
        }
    }
    return dummyHead->next;
}
//创建新链表法
struct ListNode* removeElements3(struct ListNode* head, int val) {
    struct ListNode* phead = NULL;
    struct ListNode* ptail = NULL;

    struct ListNode* pcur = head;
    while (pcur) {
        if (pcur->val != val) {
            if (phead == NULL) {
                phead = ptail = pcur;
            }
            else {
                ptail->next = pcur;
                ptail = ptail->next;
            }
        }
        pcur = pcur->next;
    }
    if (phead) {
        ptail->next = NULL;
    }
    return phead;
}
//双指针法
struct ListNode* removeElements(struct ListNode* head, int val) {
    while (NULL != head && head->val == val) {
        head = head->next;
    }
    struct ListNode* pcur = head;
    struct ListNode* prev = head;
    while (pcur)
    {
        if (pcur->val != val)
        {
            prev = pcur;
        }
        else
        {
            prev->next = pcur->next;
        }
        pcur = pcur->next;
    }
    return head;
}
//递归做法
struct ListNode* removeElements2(struct ListNode* head, int val) {
    if (head == NULL) {
        return head;
    }
    head->next = removeElements(head->next, val);
    if (head->val == val)
    {
        return head->next;
    }
    else
    {
        return head;
    }
}

2.3 收获

  • 创建虚拟头节点:好处是可以只维护一个指针
  • 创建新链表法:思路简单:仅仅为挑选符合条件的数据复制即可
  • 双指针法:保存前一个链表的指针

2.4递归详解

  • 停止条件:当遍历链表的指针为空时。
  • 如何递归:判断节点值是否等于给定值,并决定是否要删除。

三、反转链表

3.1 题目

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

3.2 题解

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL) {
        return head;
    }
    struct ListNode* a = NULL;
    struct ListNode* b = head;
    struct ListNode* c = head->next;

    while (b) {
        b->next = a;
        a = b;
        b = c;
        if (c) {
            c = c->next;
        }
    }
    return a;
}

3.3 解释

三指针法:循环保留三个指针,修改朝向即可;

四、合并两个有序列表

4.1 题目

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

4.2 题解

 //创建新链表法
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
    {
        return list2;
    }
    if (list2 == NULL)
    {
        return list1;
    }
    if (list1 == NULL && list2 == NULL)
    {
        return NULL;
    }
    struct ListNode* l1 = list1;
    struct ListNode* l2 = list2;
    struct ListNode* newhead;
    struct ListNode* newtail;
    newhead = newtail = NULL;
    while (l1 && l2)
    {
        if (l1->val < l2->val)
        {
            if (newhead == NULL)
            {
                newhead = newtail = l1;
            }
            else
            {
                newtail->next = l1;
                newtail = newtail->next;
            }
            l1 = l1->next;
        }
        else
        {
            if (newhead == NULL)
            {
                newhead = newtail = l2;
            }
            else
            {
                newtail->next = l2;
                newtail = newtail->next;
            }
            l2 = l2->next;
        }
    }
    if (l1 == NULL && l2 != NULL)
    {
        newtail->next = l2;
        while (l2->next)
        {
            l2 = l2->next;
        }
        newtail = l2;
    }
    if (l2 == NULL && l1 != NULL)
    {
        newtail->next = l1;
        while (l1->next)
        {
            l1 = l1->next;
        }
        newtail = l1;
    }
    return newhead;
}
//递归
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode* l1 = list1;
    struct ListNode* l2 = list2;
    if (l1 == NULL) {
        return l2;
    }
    if (l2 == NULL) {
        return l1;
    }
    if (list1 == NULL && list2 == NULL)
    {
        return NULL;
    }
    if (l1->val <= l2->val) {
        l1->next = mergeTwoLists(l1->next, l2);
        return l1;
    }
    l2->next = mergeTwoLists(l1, l2->next);
    return l2;
}

4.3 递归详解

  • 停止条件:当两个链表都为空时。
  • 如何递归:我们判断两个头结点哪个更小,然后较小结点的 next 指针指向其余结点。
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值