链表常见算法题二:删除定值节点,删除重复元素的所有节点、反转链表

LeetCode题目描述:移除链表元素

删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

解题思路:首先保证链表不为空(代码3-6行),由于链表首元素未判断(题目给的链表为不带头结点链表),因此第一步先找到到第一个数据不等于val的节点(代码8-24行)。第二步再对链表中的每个节点的数据进行判断,因为要删除节点,所以需要每次判断后继节点数据和val值,如果后继节点需要删除,则遍历指针不后移,若不删除后继指针,则遍历指针继续向后遍历

当然还有操作更简单的创建头指针法解决,具体可以看下一道题的另一种方法实现!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val){
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode* cur=head;
    while(1)
    {
        if(cur==NULL)//当链表中只有被删元素时,前面删除完之后链表为空
        {
            return NULL;
        }
        if(cur->val==val)
        {
            struct ListNode*tmp=cur;
            cur=cur->next;
            free(tmp);
        }
        else
        {
            break;//cur结点不为空且cur结点的数据与val不等
        }
    }
    head=cur;
    for(;cur->next!=NULL;)
    {
        if(cur->next->val == val)
        {
            struct ListNode* tmp=cur->next;
            cur->next=cur->next->next;
            free(tmp);
        }
        else
        {
            cur=cur->next;
        }
    }
    return head;
}

图解:
范例 6->6->1->2->6->3->4->5->6
在这里插入图片描述

LeetCode题目描述:删除重复节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,
链表1->2->3->3->4->4->5
处理后为 1->2->5**
思路分析:本题其实是上一个题的变种。只不过这次的val值是变化的,只要重复该节点,则val=node->val;
首先判断每个节点和后续节点是否重复,若重复就保存该节点的val值,然后不断删除后面和val值相同的节点,直到遇到和val不同的节点,说明删除完毕,接着下次判断。
若不重复就继续向后遍历判断。
这里有一个开始困扰的情况就是如果头结点就是重复节点,那么该如何删除全部重复节点?
这里有两种解决办法:

  • 先不断删除头部重复节点,直到找到第一个不重复的节点作为结束时返回的头结点,若在删除过程中遇到NULL说明该链表中所有节点均有重复;然后再对后继节点和后继next节点的next值判断,若val值相同,则按照上面的解题思路删除重复节点即可
  • 另一种就是为了统一操作,申请一个新节点作为头结点,直接按照上面的解题思路遍历就Ok了。

这里代码给出来两种方法的代码实现:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        int data=0;
        if(pHead==NULL)
        {
            return NULL;
        }
        ListNode *cur=pHead;
        ListNode*tmp=NULL;
        for(;cur!=NULL&&cur->next!=NULL;)//头结点就出现元素重复,先找到第一个不重复的节点
        {
            if(cur->val==cur->next->val)//节点重复
            {
                data=cur->val;
                while(cur!=NULL&&cur->val==data)
                {
                    //删除cur节点及之后与cur数据重复的节点
                    tmp=cur;
                    cur=cur->next;
                    free(tmp);
                }
                if(cur==NULL)
                {
                    return NULL;
                }
            }
            else
            {
                break;//cur和cur->next的数据不重复,说明cur节点为第一个不重复节点
            }
        }
        pHead=cur;
        for(;cur!=NULL&&cur->next!=NULL&&cur->next->next!=NULL;)
        {
            if(cur->next->val==cur->next->next->val)//判断cur的后继节点是否为重复节点
            {
                data=cur->next->val;
                while(cur->next!=NULL && cur->next->val==data)
                {
                    //删除cur之后和data相同的节点
                    tmp=cur->next;
                    cur->next=cur->next->next;
                    free(tmp);
                }
            }
            else
            {
                cur=cur->next;
            }
        }
        return pHead;
    }
};

创建头结点解法:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if(pHead==NULL)
        {
            return NULL;
        }
        int data;
        ListNode*cur=(ListNode*)malloc(sizeof(ListNode));//创建一个头结点,防止传入的头结点就存在重复的情况
        cur->next=pHead;
        ListNode*head=cur;//记录头结点,防止cur遍历后丢失头结点
         ListNode*tmp=NULL;
        while(cur->next!=NULL&&cur->next->next!=NULL)
        {
            if(cur->next->val==cur->next->next->val)
                //对cru之后的节点进行判断,如果重复,进入内部循环删除和data相同值的节点
            {
                data=cur->next->val;
                while(cur->next!=NULL&&cur->next->val==data)//删除和data数据相同的cur->next
                {
                    tmp=cur->next;
                    cur->next=cur->next->next;
                    free(tmp);
                    tmp=NULL;
                }
            }
            else
            {
                cur=cur->next;
            }
        }
        pHead=head->next;
        free(head);//释放19行创建的新节点
        return pHead;
    }
};

以创建头结点法为例作以图解:
用例:1->1->1->2->2->3->4->4->5
在这里插入图片描述

LeetCode题目描述:反转一个链表

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

解题思路:
采用指针指向掉头的方法迭代实现,需要注意保存每次掉头的新链表头结点和旧链表的头结点,,然后每次需要一个指针记录即将调转指向节点的后继节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL)
    {
        return;
    }
    struct ListNode* cur=head->next;
    struct ListNode* tmp=head;
    tmp->next=NULL;
    while(cur!=NULL)
    {
        struct ListNode*p=cur->next;
        cur->next=tmp;
        tmp=cur;
        cur=p;
    }
    head=tmp;
    return head;
}

图解:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值