单手杀穿经典链表题Pt.1——LeetCode天梯渡劫

目录

    • 传统艺能
    • 移除链表元素
    • 反转链表
    • 链表的中间结点

传统艺能

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
乔乔的gitee代码库(打灰人 )欢迎访问,点我!

非科班转码社区诚邀您入驻
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我

你觉得今天打打球没关系,下次你就会觉得明天躺在宿舍玩玩手机也没关系,不要低估你的实力,却不能高估你的毅力,只有优秀成为一种习惯你才不会优柔寡断,唯唯诺诺,当你还没有成功的那一刻,你什么都不是,只有成功之后,你放屁都是香的,你之所以没有这种感觉就是因为你还没有成功。 -------摘自托马斯-酷涛大佬原文

单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第1张图片

移除链表元素

链接:移除链表元素

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

示例 :
输入:head = [1,2,3,2,1], val = 2
输出:[1,3,1]
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第2张图片
思路:
我的评价是有手就行,就相当于链表的删除操作,进行遍历,遍历过程中找到目标值进行覆盖就行,注意一下这里我们采用哨兵位节点,也称为哑节点,开辟出来指向链表头节点,可以使对头节点的操作变简单很多,这个哨兵位节点的值可以不考虑,他只是用来攀搭头结点的舔狗(呜呜)。
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* dummyHead = malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode* curr = dummyHead;//定义哨兵位节点

    while (curr->next) {
        if (curr->next->val == val) {
            curr->next = curr->next->next;//遍历到目标点进行覆盖
        } 
        else 
        {
            curr = curr->next;
        }
    }
    head = dummyHead->next;
    free(dummyHead); //有借有还,记得归还哨兵位节点和申请的空间  

    return head;
}

反转链表

链接:反转链表

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

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

单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第3张图片
思路:
1.创建一个新的中间节点我命名为 next ,将当前节点的下一个节点存放在next 节点中
2.链接 next 和当前节点,将 next 指向 当前节点实现反转,将原来指向下一节点的内容销毁掉(头部指向NIULL即可);
3.重复上述过程即可

以上是整体思路实现,而代码实现我们有两条路可以走,分别是迭代和递归,实现思路是一样的:

迭代:

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

递归:

递归又分为了向前递归和向后递归,一般采用从前向后递归:

struct ListNode* reverse(struct ListNode* cur,struct ListNode* prev)
{
if(cur==NULL)
{
    return prev;
}
 struct ListNode* next = cur->next;
cur->next = prev;
return reverse(next,cur); //可以与双指针法对比,其实逻辑是一样的,只是用递归实现而已
}

struct ListNode* reverseList(struct ListNode* head)
{
return reverse(head,NULL);
}

从后向前递归:

struct ListNode* reverseList(struct ListNode* head)
{
if(!head || !head->next)
return head;
struct ListNode* cur =  reverseList(head->next);//反转第二个节点后的所有节点
head->next->next = haed;//反转第二个节点与头节点
head->next = NULL;//头节点处理

return cur;
}

~
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第4张图片

链表的中间结点

链接:链表的中间结点

给定一个头结点为 head 的非空单链表,返回链表的中间结点,如果有两个中间结点,则返回第二个中间结点。

奇数个返回中间节点:
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第5张图片
偶数个返回了两个节点中的后一个:
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第6张图片
思路:
方法一就是老老实实去遍历链表,算出链表长度,再找出中间节点位置,走过去返回他,属于暴力求解,笨且效率不高,这里就不做代码展示;
方法二巧用快慢指针,如下图:
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第7张图片
我们定义两个指针,慢指针一次走一步,快指针一次走两步,不管链表节点数是奇是偶,慢指针最后必定落在中间节点;当链表节点为偶数个时,最后快指针将落在最后一个节点上,所以只需要判断快指针的 next 节点为不为空即可

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* guard = malloc(sizeof(struct ListNode));
    guard->next = head;//定义哨兵位节点
struct ListNode* fast = guard;
struct ListNode* slow = guard;
while(fast)
{
    slow = slow->next;//慢指针一次走一步
    if(fast->next)
    {
    fast = fast->next->next;//快指针一次走两步
    }
    else
    {
        return slow;
    }
}
return slow;
}

~
单手杀穿经典链表题Pt.1——LeetCode天梯渡劫_第8张图片

今天就先到这里吧,摸了家人们。

你可能感兴趣的:(C语言,数据结构,算法,数据结构,链表,算法,leetcode)