链表之删除单链表中的重复节点

本文详细介绍了如何删除未排序链表中的重复节点,提供了三种不同的解题思路:双指针法、集合辅助法和标记数组法。每种方法都通过示例代码进行了解释,适用于链表长度在[0,20000]范围内的问题。

删除单链表中的重复节点

力扣链接

题目描述

编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。

 示例1:
 输入:[1, 2, 3, 3, 2, 1]
 输出:[1, 2, 3]
 示例2:
 输入:[1, 1, 1, 1, 2]
 输出:[1, 2]

提示:

  1. 链表长度在[0, 20000]范围内。
  2. 链表元素在[0, 20000]范围内。
解题思路

思路一:

  • 定义两个指针current和p来逐个遍历链表
    • current指向的元素依次与p指向的元素的下一个元素进行比较
      • 若相同则删去p的下一个元素【即使p的next指向下下个元素(p的next的next),继续循环比较】
      • 若不相同则p往后移动一个位置,继续循环比较,直到p所指元素的下一个为空【只要后一个不为空则继续比较,否则 停止本次比较】
    • 若所有元素都与后面元素比较过了,则返回当前链表head

思路二:

  • 定义p指针遍历链表,利用set,遇到一个元素就去set中找是否包含这个元素
    • 如果set中包含了当前元素,就说明当前遍历的元素属于重复节点,则删除
      • 利用s.count查询函数,返回的是一个整数,表示查询到元素的个数
    • 如果不包含,则添加进set中,并将p指针后移

思路三:利用标记数组,标记当前值是否出现过

代码实现

//提供完整的代码,可以在C编辑器中进行测试

#include <iostream>
#include <set>

using namespace std;

struct ListNode{
	int val;
	ListNode *next;
	ListNode(int x) : val(x),next(NULL){}
}; 

class Solution{
public:
	//方法一: 
	ListNode* removeDuplicateNodes(ListNode* head){
		//判断是否需要遍历
        if(head==NULL||head->next==NULL) return head;
		
		ListNode* current = head;
		while(current){//第一重循环:将第i个元素依次与后面元素进行比较(i从1到最后)
			ListNode *p = current;
			while(p->next){//第二重循环:与后1个比、后2个比、后三个比...与最后一个比
				if(p->next->val == current->val){
					p->next = p->next->next;//删除p后面这个重复的元素
				}else{
					p = p->next;//p后移
				}
			}
			current = current->next;//将第i+1个元素开始依次与后面元素进行比较
		}
		return head;//这里返回的一定是head,此时的head后面的链表已经删除了重复的元素 
	}

	//方法二: 
	ListNode* removeDuplicateNodes2(ListNode* head){
		if(head==NULL||head->next==NULL) return head;
		
		set<int> s;
		
		ListNode* p = head;
		s.insert(p->val);
		
		while(p->next){//只要还没到最后一个元素,就遍历
			if(s.count(p->next->val)!=0){//包含了,则重复
				p->next = p->next->next; 
			}else{						//不重复,添加进去、后移
				s.insert(p->next->val);	//或者可以先后移再添加,p=p->next;s.insert(p->val);
				p = p->next;
			}
		}
		return head;
	}
    
    //方法三:
	 ListNode* removeDuplicateNodes3(ListNode* head){
	 	if(head==NULL||head->next==NULL) return head;
	 	
	 	//利用val的值在0~20000之间,标记是否出现过 
	 	int index[20001] = {0};
	 	index[head->val] = 1;
	 	
	 	struct ListNode* q = head;
	 	
	 	while(q->next){
	 		//下一个val未出现过,保存下一个val 
	 		if(index[q->next->val]==0){
	 			index[q->next->val] = 1;
	 			q = q->next;
			 }else{							//下一个val出现过,删除下一个节点 
			 	q->next = q->next->next;
			 }
		 }
		 return head;
	 }
	
    //链表打印函数
	void ListPrintf(ListNode* head){
		
		ListNode* pos = head;
	 
		while(pos){
			cout<<pos->val<<"->";
			pos = pos->next; 
		}
		cout <<"NULL"<<endl;	
	}
	
    //尾部插入函数
	void ListBackInsert(ListNode** pphead,int val){
		ListNode* newNode = new ListNode(val);
		
		if(*pphead==NULL){
			*pphead = newNode;
		}else{
			ListNode* pos = *pphead;
			
			while(pos->next!=NULL){
				pos = pos->next;
			}
			pos->next = newNode;
		}
	} 
};


int main(){
	ListNode* test = new ListNode(1);
	ListNode* result;
	
	class Solution s;	
	
	s.ListBackInsert(&test,2);
	s.ListBackInsert(&test,3);
	s.ListBackInsert(&test,3);
	s.ListBackInsert(&test,2);
	s.ListBackInsert(&test,1);
	s.ListPrintf(test);
	
	result = s.removeDuplicateNodes(test);
	//result = s.removeDuplicateNodes2(test);
	//result = s.removeDuplicateNodes3(test);
	s.ListPrintf(result);

	return 0;
}

结果:
image-20221127180021258

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值