数据结构与算法每日一练---链表---0x0000

本文介绍了三种不同的方法来解决LeetCode上的203题,即在链表中删除所有值等于给定值的节点。方法包括常规迭代法、使用虚拟头节点和借助C++ STL库。每种方法都详细解析了实现思路,强调了处理特殊情况,如删除头节点的情况。
摘要由CSDN通过智能技术生成

移除链表元素

LeetCode题号:203

所属类型:链表

题目

说明

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

示例

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

输入:head = [], val = 1
输出:[]

输入:head = [7,7,7,7], val = 7
输出:[]

提示

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

题解

  • 链表节点
struct ListNode
{
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

方法1:常规方法

class Solution 
{
public:
    ListNode* removeElements(ListNode* head, int val)
    {
        ListNode* pPre = nullptr;
        ListNode* pCur = head;
        
        // 遍历链表,每个节点的值与目标值进行比对
        while (nullptr != pCur)
        {
            if (pCur->val == val)
            {
                pCur = DeleteNode(head, pPre, pCur);
            }
            else
            {
                pPre = pCur;
                pCur = pCur->next;
            }
        }

        return head;
    }

    /**
     *@brief 删除节点函数,并返回被删除节点的下一个节点
     */
    ListNode* DeleteNode(ListNode*& pHead, ListNode* pPre, ListNode* pDelete)
    {
        // 获取被删除节点的下一个节点
        ListNode* pNext = pDelete->next;

        // 当pPre为nullptr时,实则删除的节点就是头结点
        nullptr == pPre ? pHead = pNext : pPre->next = pNext;

        delete pDelete;
        return pNext;
    }
};
  • 方法分析:
    封装了一个删除节点的函数,函数的传入参数有三个
  1. ListNode*& pHead:头结点指针引用 ,目的是在删除节点为头结点时更新头结点
  2. ListNode* pPre :删除节点的前驱节点
  3. ListNode* pDelete:删除节点
    返回值为被删除节点的后一个节点

所以我们只需要对链表进行遍历,让每个节点的值域与目标值进行比对,相同则调用删除函数,不同则进行下一个节点的比对。

方法2:虚拟头节点

class Solution 
{
public:
    ListNode* removeElements(ListNode* head, int val)
    {
        // 创建一个虚拟头结点
        ListNode* pDummyHead = new ListNode(0, head);
        ListNode* pTemp = pDummyHead;

        // 采用 pTemp->next 的方式实际时处理的 pTemp 的下一个节点
        while (nullptr != pTemp->next)
        {
            if (pTemp->next->val == val)
            {
            	// 获取删除节点
                ListNode* pDelete = pTemp->next;
                // 将被删除的节点跳过
                pTemp->next = pTemp->next->next;
                delete pDelete;
            }
            else
            {
                pTemp = pTemp->next;
            }
        }

        head = pDummyHead->next;
        delete pDummyHead;

        return head;
    }
};
  • 方法分析:
    创建了一个虚拟的头节点pDummyHead,将遍历指针指向虚拟头节点,开始遍历整个链表。当pTemp指向pDummyHead时,我们处理的实际上是pTemp的后继节点,当pTemp的位置位于链表倒数第二个节点时,其next为最后一个节点,此时处理最后一个节点,当pTemp指向最后一个节点时,此时的后继节点为空,处理完成。这个方法的好处是不需要变量存储被删除节点的前驱节点。所有的节点都可以统一方式处理。

方法3:采用C++ STL库处理

class Solution 
{
public:
    ListNode* removeElements(ListNode* head, int val) 
    {  
        vector<ListNode*> vecTempNode;		// 不删除的节点
        vector<ListNode*> vecDeleteNode;	// 删除的节点

        ListNode* pCur = head;
        while (nullptr != pCur)
        {
            pCur->val == val ? vecDeleteNode.push_back(pCur) : vecTempNode.push_back(pCur);
            pCur = pCur->next;
        }
		
		// 释放删除的节点内存
        Release(vecDeleteNode);
		
		// 连接不删除的节点构成新链表
        head = LinkVecNode(vecTempNode);
        
        return head;
    }
	
	// 释放vector里面的节点
    void Release(vector<ListNode*>& vecNode)
    {
        if (vecNode.empty())
            return;

        for (size_t i = 0; i != vecNode.size(); ++i)
        {
            if (nullptr != vecNode[i])
                delete vecNode[i];    
        }    

        vecNode.clear();
    }
	
    ListNode* LinkVecNode(vector<ListNode*>& vecNode)
    {
        if (vecNode.empty())
            return nullptr;
		
		// 找到头节点
        ListNode* pHead = vecNode[0];
        ListNode* pTemp = pHead;

        for (size_t i = 1; i != vecNode.size(); ++i)
        {
        	// 方法一
            pTemp->next = vecNode[i];
			
			// 方法二:做一次判断,再看用不用赋值,因为有可能有些节点本身就是连接状态的
			/*
        	if (pTemp->next != vecNode[i])
            	pTemp->next = vecNode[i];
            */
            
            pTemp = pTemp->next;    
        }    
		// 此时pTemp指向的是最后一个节点
		// 一定要将其next置位空,否则next可能指向已经被删除的节点
        pTemp->next = nullptr;
        return pHead;
    }
};
  • 方法分析:
    采用了两个vector<ListNode*>分别存储不用删除的节点和需要删除的节点,然后清空需要删除节点的内存,再链接不被删除的节点,从而构成题目所需的链表,要注意的是在链接不被删除的链表时,一定要将最后一个节点的next指针域值为空,否则可能出错,比如:
    【1, 2, 3, 4, 5】 目标删除值为5时,当进行每个节点的分类后,再链接不被删除的节点时最后一个节点是4,但此时它的next指针域并不为空,而是继续指向了被删除的节点5,所以需要手动将4的next置位空。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值