题目:删除有序链表中重复的元素

描述:给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:给出的链表为1→2→3→3→4→4→5,返回1→2→5。
给出的链表为1→1→1→2→3,返回2→3。

示例1输入:{1,2,2},返回值:{1}


解法一:

思路分析:可以利用双指针法,首先我们可以设置一个newhead对象,pre = newhead,cur = head,在已知head的情况下,我们开始循环判断cur对象,设置循环条件为cur ->next不为空,判断cur->val是否等于cur->next->val,如果等于就将count的值累加(其中count的值为链表中的重复累加元素的个数和),当有重复的情况发生,就令pre->next = cur->next,count = 0,删除该元素,始终进行如下判断,如果没有重复,就将pre链表的值变为现在cur链表的值,递归条件为cur = cur - next。

实例分析:给出的链表为1→2→3→3→4→4→5

1、首先设定newhead对象,pre对象,cur对象和count的值为0。

第一次

1

2

3

3

4

4

5


2、根据程序设定,令nexhead = {0,1,2,3,3,4,4,5},pre: {0,1,2,3,3,4,4,5},cur: {1,2,3,3,4,4,5},判断cur ->next是否为空,不为空,判断cur->val是否等于cur->next->val,不等于,则说明第一个与第二个不为重复元素,则将pre与cur进行同步,将cur设定为cur - next。

第二次

2

3

3

4

4

5


3、再次循环,继续进行判断。

第三次

3

3

4

4

5

4、当发现重复的元素,将count的值累加,count = 1,在进行一次循环后将pre->next = cur->next,count = 0,如此pre = {2,4,4,5},cur = {4,4,5}。

第四次

4

4

5

5、通过上述重复进行判断,最终输出结果。

具体C++代码为:


/**
 * struct ListNode {
 *    int val;
 *    struct ListNode *next;
 * };
 */
 
class Solution {
public:
    /**
     *
     * @param head ListNode类
     * @return ListNode类
     */
    ListNode* deleteDuplicates(ListNode* head) {
        // write code here
        ListNode* newhead = new ListNode(0);//设置一个初始链表
        newhead->next = head;//将head链表添加到newhead中
        ListNode* pre = newhead;
        ListNode* cur = head;
        int count = 0;//设置重复次数
        while(cur != NULL && cur->next != NULL){//判断条件
            if(cur->val == cur->next->val){//如果按照顺序,值相等
                cur->next = cur->next->next;//删除该元素
                count++;//将count次数加一再次进行判断
            }
            else{
                if(count > 0){
                    pre->next = cur->next;//将该元素值全部删除
                    count = 0;
                }
                else
                    pre = cur;
                cur = cur->next;//递归条件
            }
        }
        if(count > 0)//存在比如{1,2,2},因为删除,所以上述循环条件不进行判断,在此额外进行判断
            pre->next = cur->next;
        return newhead->next;
    }
};


将所有链表的值进行判断,除了当倒数第二个值与最后一个值相等的话,其他情况下,需要遍历链表中的全部元素,故时间复杂度为O(N),空间复杂度为O(N)。


解法二:

思路分析:使用递归的方法去求解,当head后面存在值且与head的值相等的话,那么就一直向后找,直到找到不相等的值为止,然后对后面的那个结点进行递归,删除前面重复的结点,如果head的值与head.next的值不相等的话,那么就递归后面的结点,最后返回head变量。

实例分析:给出的链表为1→2→3→3→4→4→5

1

2

3

3

4

4

5

递归

递归

删除

删除

删除

删除

递归

返回

返回

返回

返回head链表1→2→5


具体java代码为:


import java.util.*;
 
/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */
 
public class Solution {
    /**
     *
     * @param head ListNode类
     * @return ListNode类
     */
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null){
            return null;
        }
        if(head.next != null && head.val == head.next.val){//发现有重复值
                while(head.next != null && head.val == head.next.val){
                    head = head.next;//删除
            }
            return deleteDuplicates(head.next);//把与删除的那个结点相同的结点也进行删除
        }
        head.next = deleteDuplicates(head.next);//当没有发现重复值的情况,就一直进行递归操作
        return head;
    }
}


递归操作,将链表元素值进行递归,重复递归导致其时间复杂度为O(N),因为没有占用任何的内存空间,所以其空间复杂度为O(1)。