82.删除排序链表中的重复元素(递归与非递归)
存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。
返回同样按升序排列的结果链表。
解法一、非递归遍历
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode p = head,h = new ListNode(0),ht = h; //虚拟头节点
int val = -101;
while(p != null && p.next != null){
if(p.val == p.next.val){
val = p.val
while(p != null && p.val==val) p=p.next; //排除重复部分
}else{ //可以插入
ht.next = p;
ht = p;
p = p.next;
}
}
//尾结点特殊处理
if(p!=null && p.val != val) {
ht.next = p;
ht=p;
}
ht.next = null;
return h.next;
}
}
解法二、递归
从左到右,递归过程中做处理,递归完成,答案也完成;
递归边界:结点为空,或到了尾结点
非边界返回值:已经去重的链表的头结点
每一步做什么: 判断当前结点是否和去重的链表的头结点值相同,若相同,开始跳过结点,如不同,连接上
public static ListNode deleteDuplicates(ListNode head) {
//baseCase
if (head == null || head.next == null) {
return head;
}
ListNode next = head.next;
//如果是这种情况
// 1 --> 1 --> 1 --> 2 --> 3
// head next
//1.则需要移动next直到出现与当前head.value不相等的情况(含null)
//2.并且此时的head已经不能要了,因为已经head是重复的节点
//--------------else-------------
// 1 --> 2 --> 3
// head next
//3.如果没有出现1的情况,则递归返回的节点就作为head的子节点
if (head.value == next.value) {
//1
while (next != null && head.value == next.value) {
next = next.next;
}
//2
head = deleteDuplicates(next);
} else {
//3
head.next = deleteDuplicates(next);
}
return head;
}
补充:如果问题变为「相同节点保留一个」,该如何实现?
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode p = head, dummy = new ListNode(0), ht = dummy;
if(head==null) return null;
while(p!=null){
while(p.next!=null && p.val == p.next.val) p = p.next; //跳到重复结点的最后一个
ht.next = p; //尾插
ht = ht.next;
p = p.next;
}
return dummy.next;
}
}
//递归 从右到左,先递归到边界
递归边界:结点为空,或到了尾结点
非边界返回值:已经去重的链表的头结点
每一步做什么: 判断当前结点是否和去重的链表的头结点值相同,若相同,删节点,如不同,连接上
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
head.next = deleteDuplicates(head.next);
if(head.val == head.next.val) head = head.next;
return head;
}
}