• 力扣(leetcode)刷题分享,简单题(第2期)


    第二期介绍

    本期博客主要讲解的题目是有关链表的一些经典OJ题,有一定难度,希望大家耐心看完。

    1. 反转链表

    题目介绍:
    给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
    OJ链接
    思路分析:定义一个新头,将原链表的元素依次头插致新头后面,最后返回新头。
    时间复杂度:O(N)
    图解:
    在这里插入图片描述
    代码实现:

    struct ListNode* reverseList(struct ListNode* head)
    {
        struct ListNode* rehead=NULL;//新头
        struct ListNode* cur=head;
        while(cur)//遍历链表
        {
            struct ListNode* tmp=cur;
            cur=cur->next;
            //头插
            tmp->next=rehead;
            rehead=tmp;
        }
        return rehead;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2. 移除链表元素

    题目介绍:
    给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点 。
    OJ链接
    思路分析:
    方法1:遍历数组,找到目标元素后将其删除。
    时间复杂度:O(N^2)
    该算法思路简单,但是效率较低,所以我们这里就不使用它了
    方法2:声明一个新的头,遍历原链表,不为val就将原链表的元素尾插到新链表中。
    时间复杂度:O(N)
    图解:
    在这里插入图片描述

    代码实现:

    struct ListNode* removeElements(struct ListNode* head, int val)
    {
    	//声明新头和新尾
    	struct ListNode* newhead = NULL, * newtail = NULL;
    	//遍历原链表
    	struct ListNode* cur = head;
    	while (cur)
    	{
    		//如果原链表的元素不为val就尾插到新链表中
    		if (cur->val != val)
    		{
    			struct ListNode* tmp = cur;
    			cur = cur->next;
    			//新链表为空的情况
    			if (newhead == NULL)
    			{
    				tmp->next = NULL;
    				newtail = newhead = tmp;
    			}
    			//一般情况
    			else
    			{
    				tmp->next = NULL;
    				newtail->next = tmp;
    				newtail = newtail->next;
    			}
    		}
    		else
    		{
    			cur = cur->next;
    		}
    	}
    	return newhead;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3. 找链表的中间节点

    题目介绍:
    给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
    OJ链接
    思路:快慢指针。定义一对快慢指针,其中slow指针每次只走一步,fast指针每次走两步,当fast指针遍历完链表时,slow指针就停在链表中间了。
    注意需要分类讨论链表结点个数为偶数还是奇数
    图解:
    请添加图片描述
    请添加图片描述
    代码实现:

    struct ListNode* middleNode(struct ListNode* head)
    {
        struct ListNode* slow,*fast;
        slow=fast=head;
        while(fast&&fast->next)
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        return slow;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4. 寻找链表中的倒数第k个结点

    题目介绍:输入一个链表,输出该链表中倒数第k个结点。
    OJ链接
    思路分析:快慢指针。快指针先走k步,然后两个指针一起走,当快指针走到空时,慢指针就走到目标结点了。
    图解:
    请添加图片描述

    代码实现:

    struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
    {
        struct ListNode* fast=pListHead,*slow=pListHead;
        //如果链表为空 直接返回NULL
        if(pListHead==NULL)
        {
            return NULL;
        }
        //快指针先走k步
        while(k)
        {
            //如果快指针已经为空了,但是k还不为0,说明k比链表总长度都大,直接返回NULL
            if(fast==NULL)
            {
                return NULL;
            }
            fast=fast->next;
            k--;
        }
        while(fast)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    5. 合并两个有序链表

    题目介绍:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
    OJ链接
    思路分析:创建一个新头,将两个链表的元素依次对比,每次都将链表中较小(或者相等)的元素尾插到新头后,有一个链表为空时就停止对比,再将不为空的链表链接到新链表后。
    图解:
    请添加图片描述
    代码实现:

    1. 不带表头版(比较麻烦)
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
    {
        struct ListNode* newhead=NULL;
        struct ListNode* newtail=NULL;
        //判断特殊情况
        if(!list1)
        {
            return list2;
        }
        if(!list2)
        {
            return list1;
        }
        //只要有一个链表遍历完就退出循环
        while(list1&&list2)
        {
            if(list1->val<=list2->val)
            {
                struct ListNode* tmp=list1;
                list1=list1->next; 
                tmp->next=NULL;
                if(newhead==NULL)
                {
                    newtail=newhead=newtail=tmp;
                }
                else
                {
                    newtail->next=tmp;   
                    newtail=newtail->next;
                }
            }
            else
            {
                struct ListNode* tmp=list2;
                list2=list2->next; 
                tmp->next=NULL;
                if(newhead==NULL)
                {
                    newtail=newhead=newtail=tmp;
                }
                else
                {
                    newtail->next=tmp;   
                    newtail=newtail->next;
                }
            }
        }
        //循环结束后,将剩下的节点链接致新链表后面
        if(list1)
        {
            newtail->next=list1;
        }
        if(list2)
        {
            newtail->next=list2;
        }
        return newhead;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    1. 带表头版
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
    {
        //申请表头
        struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
        newhead->next=NULL;
        struct ListNode* cur=newhead;
        while(list1&&list2)
        {
            if(list1->val<=list2->val)
            {
                cur->next=list1;
                list1=list1->next;
            }
            else
            {
                cur->next=list2;
                list2=list2->next;
            }
            cur=cur->next;
        }
        if(list1)
            cur->next=list1;
        if(list2)
            cur->next=list2;
        struct ListNode* tmp=newhead->next;
        free(newhead);
        return tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    总结

    本期博客主要讲解了一些比较基础,简单的题目,感谢大家耐心看完,下一期会提升一点难度。大家加油!
    在这里插入图片描述

  • 相关阅读:
    NeurIPS2022 interesting papers
    3.2 自定义函数
    2023年上半年软考网工选择题易错总结
    视频批量剪辑工具,自定义视频速率,批量剪辑工具助力创意无限”
    期末复习 C语言再学习
    ESP8266 做简单的仪器
    BUG系列路径规划算法原理介绍(六)——BugFlood算法
    一位平凡毕业生的大学四年
    使用Flask开发简单接口
    深度学习【fastText原理解析】
  • 原文地址:https://blog.csdn.net/m0_72482689/article/details/127825584