删除链表重复元素(一题三解)
一、迭代法
public ListNode recursion_deleteDuplicates(ListNode head){
ListNode dummy = new ListNode();
dummy.next = head;//不加哑节点的话,就要用注释里那条,我没看懂
if(head == null){//当前遍历到头了
return null;
}else if(head.next == null){//当前遍历到头了
return head;
}else{//确保至少有两个节点时
if(head.val == head.next.val){//head也要被删,包括头在内,所有相同值的都不能要
ListNode tmp = head;//head.next
while (tmp != null && tmp.val == head.val){
tmp = tmp.next;
}
//此时tmp是第一个值与前面一堆不同的,从它开始才有可能保留下来
dummy.next = recursion_deleteDuplicates(tmp);
//新的头换上去
// return deleteDuplicates(tmp);
}else{//head存活,判断head下一个接什么
head.next = recursion_deleteDuplicates(head.next);
}
}
return dummy.next;
}
二、一遍遍历
public ListNode iteration_deleteDuplicates(ListNode head){
ListNode dummy = new ListNode();
dummy.next = head;
if(head == null){//当前遍历到头了
return null;
}else if(head.next == null){//当前遍历到头了
return head;
}//故技重施
else{
ListNode pre = dummy;
ListNode cur = head;
while (cur != null){
while (cur.next !=null && cur.val == cur.next.val){
cur = cur.next;
}//cur走到相同元素的最后一个
if(pre.next == cur){//说明头节点不用删除,判断下一个节点
pre = pre.next;
//这样看来的话,是pre遍历了整个数组,cur只是每次遍历决定的下一个便利的位置
}else{//换头行动,把cur后一个不属于一堆同的换上去
pre.next = cur.next;
cur = cur.next;
}
}
}
return dummy.next;
}
三、记录法(结构复杂,耗时,但想法其实很简单)
//map.getOrDefault:返回指定键映射到的值,如果此映射 不包含 键的映射,则返回 defaultValue 。
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
return (e = getNode(key)) == null ? defaultValue : e.value;
}
public ListNode count_deleteDuplicates(ListNode head){
//老规矩,这里合并一下
if(head==null||head.next==null) return head;
//使用一个map去存储结点出现的次数,大于1的就删除
ListNode cur=head;
HashMap<Integer,Integer> map=new HashMap<>();
List<Integer> l1=new ArrayList<>();
while(cur!=null){
map.put(cur.val, map.getOrDefault(cur.val, 0)+1);//有这个键就覆盖
cur=cur.next;
}
Iterator<Map.Entry<Integer, Integer>> entry_itr = map.entrySet().iterator();
//找到次数大于0的map的key
while(entry_itr.hasNext()){
Map.Entry<Integer, Integer> entry = entry_itr.next();
if(entry.getValue()>1) {
l1.add(entry.getKey());//l1中存了 重复 的点
}
}//最好记住,迭代器的遍历方式,迭代器是不是和哑指针是一个性质
ListNode pre=new ListNode();
pre.next=head;
//pre在哑指针的位置上
cur=head;
//开始遍历
while(cur!=null){
if(l1.contains(cur.val)){//说明这个cur不可取
if(cur.val==head.val) head=head.next;//cur是头的话,得换头
pre.next=cur.next;//不管是不是头,cur废了,pre的下一个指向cur的下一个
}else{
pre=cur;//可取,留着,从他开始继续遍历
}
cur=cur.next;//pre和head操作完之后,cur循环继续下一个
}
return head;
}