题意分析
- 给出一个链表,要求我们返回这个链表中的所有的元素,但是与NC25不同的是,要求这些元素是在初始的链表里面只出现一次的元素,同时这个链表的所有的元素需要保持原来的相对位置关系。这个就不是去重了。
思路分析
- 我们思考,如何把出现多次的元素在链表里面去掉呢?
- 方法还是利用哈希进行处理,我们用一个哈希表统计这个链表里面的所有的元素出现的次数。处理完之后我们就直到哪些元素需要保留了。
- 其次,我们如何保持原来的顺序呢?
- 保持原来的顺序就要我们按照链表的顺序进行访问。其实这里可以自己重新定义一些新的变量,构造出一个完完全全的新的链表。但是其实没有必要,这样对内存的浪费是很大的。其实我们可以在原来的基础上进行处理,我们只要把一些指针的next指针重新指定就行了。这里我定义了一个pre,用来处理返回答案的那条链表此时所指向的位置,然后用一个now用来进行遍历初始的链表。一旦遇到合适的结点,我就将这个pre指针的next指针指向这个结点,同时pre更新为now,依次下去。但是最后要注意的是我们需要将pre->next置为NULL。确保链表正常终止。但是这个和NC25有点不一样的就是我们的头节点需要我们进行寻找,可能不是初始链表的头节点。这里可能找不到,所以我们直接返回空即可。其次,找到之后就是按照NC25的思路进行查找,和上面的思路一样。
- 具体更新链表请看下面的图进行理解(请原谅我用的是和那题一样的图,因为思路都是一样的,就是处理有点不一样)
- 那么,答题的思路就是我们先进行哈希将这些出现多次的结点排除,然后再进行一次遍历,操作和之前的一样。最后就可以得到最终的链表了。
写法一 C++版
- 代码如下
- 我们只需要对链表进行遍历,所以时间复杂度为O(N)
- 我们需要利用哈希表存储整个链表的所有的元素,所以空间复杂度为O(N)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* deleteDuplicates(ListNode* head) {
// write code here
// 特判链表为空的情况,防止出现段错误
if(head==NULL){
return head;
}
unordered_map<int,int> mp;
ListNode* now=head;
// 先对链表进行一次遍历哈希出每个数字出现的次数
while(now){
mp[now->val]++;
now=now->next;
}
now=head;
// 找到可以作为头节点的第一个结点指针
while(now){
if(mp[now->val]==1){
head=now;
break;
}
now=now->next;
}
// 注意这里可能找不到,所以需要直接返回空
if(now==NULL){
return NULL;
}
ListNode* pre=now; // 找到了就用一个pr先存着
now=now->next;
// now开始向后面进行遍历
while(now){
// 如果这个数字出现过
if(mp[now->val]==1){
pre->next=now;
pre=now;
}
now=now->next;
}
// 最后记得结尾指向null
pre->next=NULL;
return head;
}
};写法二 Go语言版
- 代码如下
- 我们只需要对链表进行遍历,所以时间复杂度为O(N)
- 我们需要利用哈希表存储整个链表的所有的元素,所以空间复杂度为O(N)
package main
import . "nc_tools"
/*
* type ListNode struct{
* Val int
* Next *ListNode
* }
*/
/**
*
* @param head ListNode类
* @return ListNode类
*/
func deleteDuplicates( head *ListNode ) *ListNode {
// write code here
if(head==nil){
return nil
}
pre := new(ListNode)
now := new(ListNode)
var mp map[int]int
mp = make(map[int]int)
now=head
// 进行一次遍历找到出现多次的数字,排除相关的结点指针
for{
if(now==nil){
break
}
mp[now.Val]+=1;
now=now.Next
}
now=head
// 再进行一次遍历找到头节点,注意不一定是初始链表的第一个节点
for {
if(now==nil){
break
}
if(mp[now.Val]==1){
pre=now
break
}
now=now.Next
}
// 没有找到头节点,直接返回nil
if(now==nil){
return nil
}
head=pre // pre用来记录最终的链表的尾部结点
now=now.Next
for {
if(now==nil){
break
}
// 如果符合题目条件,只出现过一次,那么更新pre指针
if(mp[now.Val]==1){
pre.Next=now
pre=now
}
now=now.Next
}
// 最后链表尾部指向nil
pre.Next=nil
return head
}
京公网安备 11010502036488号