力扣(leetcode)经典题目分享第2期——链表

力扣

  • 第二期介绍
  • 1. 反转链表
  • 2. 移除链表元素
  • 3. 找链表的中间节点
  • 4. 寻找链表中的倒数第k个结点
  • 5. 合并两个有序链表
  • 总结

第二期介绍

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

1. 反转链表

题目介绍:
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
OJ链接
思路分析:定义一个新头,将原链表的元素依次头插致新头后面,最后返回新头。
时间复杂度:O(N)
图解:
力扣(leetcode)经典题目分享第2期——链表_第1张图片
代码实现:

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

2. 移除链表元素

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

代码实现:

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

3. 找链表的中间节点

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

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

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

题目介绍:输入一个链表,输出该链表中倒数第k个结点。
OJ链接
思路分析:快慢指针。快指针先走k步,然后两个指针一起走,当快指针走到空时,慢指针就走到目标结点了。
图解:
力扣(leetcode)经典题目分享第2期——链表_第5张图片

代码实现:

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

5. 合并两个有序链表

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

  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. 带表头版
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;
}

总结

本期博客主要讲解了一些比较基础,简单的题目,感谢大家耐心看完,下一期会提升一点难度。大家加油!
力扣(leetcode)经典题目分享第2期——链表_第7张图片

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