Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

Example 1:

Input: 1->2->3->3->4->4->5
Output: 1->2->5  

Example 2:

Input: 1->1->1->2->3
Output: 2->3

 

这道题是LeetCode 83. Remove Duplicates from Sorted List —— 删除排序链表中的重复元素升级版。区别就是这道题不能保留重复的节点。这就引发了一个问题,如果第一个节点就是重复的要怎么办。迭代方法的话很自然的想到要建立一个假节点连到头结点前进行处理,并且要时刻保持指针指在重复节点的前驱节点上。

第一步,建立假节点链接在表头前,并建立指针指向假节点,即从假节点开始遍历链表;

第二步,判断当前指针的next以及next的next是否相同,即找到没有重复值得节点,此时注意前驱节点要一直保留,即只移动next指向的节点,见代码;

第三步,将当前指针的next指向第一个没有重复过的节点,后移指针,并重复上述过程。

 

递归方法还是更容易直观简洁一些:

先看头节点是不是重复的,如果是重复的,那就从头结点后第一个非重复节点(这里的非重复节点是指和头结点值不同的节点,而不是在整个链表不存在重复值的节点)开始重新调用函数;

如果头结点不是重复的,那么递归调用头结点之后的节点。

递归方法简洁吊打迭代方法,见代码。

 


迭代解法(Java)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode dummy = new ListNode(0);
        dummy.next = head; //建立假节点指向表头
        head = dummy; //建立指针从假节点遍历,这里用head作为指针节省一点儿空间
        while (head.next != null && head.next.next != null) { //特殊情况处理,即空链表和单节点的链表
            if (head.next.val == head.next.next.val) { //找到后继中第一个不重复的节点
                int val = head.next.val; //记录一下后继的值,便于后面搜索
                while(head.next != null && head.next.val == val) 
                    head.next = head.next.next; //只改变后继的next域,这样做可以保证前驱一直指向重复节点的头,因此找到节点后使驱现在指向第一个不重复的节点,相当于跨过所有重复的节点
            }
            else 
                head = head.next; //将指针移动到找到的第一个不重复的节点
        }
        return dummy.next; //返回
    }
}

 

递归解法(Java)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null) return head; //处理特殊情况,即空链表和单节点链表
        ListNode cur = head.next; //建立一个指针,扫描头结点后面的节点,意为看头结点是否是重复节点
        if (cur.val != head.val) { //如果头结点不是重复节点
            head.next = deleteDuplicates(cur); //头结点的next就指向递归调用后的cur节点,cur几点就是头结点的后继
            return head; //返回全部递归调用后的头结点
        }
        else { //如果头结点是重复节点
            while (cur != null && cur.val == head.val) cur = cur.next; //找到第一个和头结点值不同的节点,并返回递归调用这个节点的结果
            return deleteDuplicates(cur);
        }
    }
}

 

posted on 2018-07-02 16:47  小T在学习  阅读(316)  评论(0编辑  收藏  举报