删除排序链表中的重复元素 II(力扣)

删除排序链表中的重复元素 II

力扣题目链接 -> 传送门
所用语言:Java
第一种方法是我自己想的,用了两次遍历,运行用时1ms,内存消耗38MB左右
第二种方法是我参照大佬的题解写的(和大佬的答案基本相似),运行用时0ms!不得不佩服大佬的细节处理


正文

解析①

可以看到,在题目的提示中结点值的范围是[-100, 100],这个范围并不是很大,我们可以使用数组来记录每个值出现的次数。

例如:我们定义一个偏移量int offset = 100,使用偏移量将结点值的范围控制在[0, 200]之内。然后我们就可以定义一个记录数组int count[] = new int[201],数组的下标val + offset表示结点值val,而count[val + offset]则表示值val出现过的次数。如果count[val + offset] > 1,表示值为val的结点是重复结点,需要删除掉。

使用上面这种思路,我们一共需要两趟遍历。第一趟遍历用来填充记录数组count;第二趟遍历用来删除重复结点。

Tip: 这是一种典型的,将数值定义转化为另一种定义,方便问题的求解。因为这个题目要求是删除所有重复的结点,所以在第二趟遍历中,count[val + offset]的值不用改变。如果是要保留一个重复结点中的一个结点,在第二趟遍历时每删除一个重复结点count[val + offset]的值就减一就好了,用来控制结点数。另外,这种方法不仅仅适用于有序链表,更适用于在无序链表中删除重复结点。(因为我一开始没有注意到链表是有序的,所以思考时代入的是对象是任何链表…(没有仔细看题真的好亏😤😤))

解析②

这个大佬的方法,则是巧妙地利用了链表是有序的这个特点。大佬的解析 -> 传送门

答案①

public ListNode deleteDuplicates(ListNode head) {
    if (head == null) {
        return head;
    }

    int count[] = new int[201];
    int offset = 100;
    ListNode list = head;

    do {
        count[list.val + offset]++;
        list = list.next;
    } while (list != null);

    list = head;
    while (list.next != null) {
        if (count[list.next.val + offset] > 1) {
            list.next = list.next.next;
        } else {
            list = list.next;
        }
    }

    // 处理头结点
    if (count[head.val + offset] > 1) {
        head = head.next;
    }
    return head;
}

答案②

public ListNode deleteDuplicates(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }

    ListNode tail = new ListNode();
    ListNode newHead = tail;

    while (head != null) {
        if (head.next == null || head.val != head.next.val) {
            tail.next = head;
            tail = head;
        } else {
            // 跳过值相同的结点
            while (head.next != null && head.val == head.next.val) {
                head = head.next;
            }
        }

        head = head.next;
    }

    tail.next = head;
    newHead = newHead.next;
    return newHead;
}

最后

个人感觉今天的这个题目是中等里面难度偏下的,题目本身做出来不是很难,难的是想到更巧妙的方案(虽然每道题都是这样)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值