链表12:链表中删除元素的8道题之三

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表12:链表中删除元素的8道题之三相关的知识,希望对你有一定的参考价值。

我们继续看第三组关于结点删除的题:

【5】LeetCode 83 存在一个按升序排列的链表,请你删除所有重复的元素,使每个元素只出现一次。

【6】LeetCode 82 存在一个按升序排列的链表,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中没有重复出现的数字。

【7】LeetCode 1836. 从未排序链表中删除重复元素。

LeetCode82和83 这两个题其实是一个,区别就是一个要将出现重复的保留一个,一个是只要重复都不要了,这种细微的差别我们处理起来并不是难事。这也再次用事实说明LeetCode不需要全部刷完,高质量刷三四百道就足够了。这里为了完整,我们还是都看一下。

LeetCode 1836虽然也是在82的基础上改了一下条件,将链表改成无序的了,这个难度要增加不少,接下来也一起分析。

1.LeetCode83 重复元素保留一个


我们还是先看题目要求:

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。

返回同样按升序排列的结果链表。

示例:

输入:head = [1,1,2,3,3]输出:[1,2,3]

由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。

具体地,我们从指针 cur 指向链表的头节点,随后开始对链表进行遍历。如果当前 cur 与cur.next 对应的元素相同,那么我们就将cur.next 从链表中移除;否则说明链表中已经不存在其它与cur 对应的元素相同的节点,因此可以将 cur 指向 cur.next。当遍历完整个链表之后,我们返回链表的头节点即可。

另外要注意的是 当我们遍历到链表的最后一个节点时,cur.next 为空节点,如果不加以判断,访问 cur.next 对应的元素会产生运行错误。因此我们只需要遍历到链表的最后一个节点,而不需要遍历完整个链表。

上代码:

class Solution {    public ListNode deleteDuplicates(ListNode head) {        if (head == null) {            return head;        }        ListNode cur = head;        while (cur.next != null) {            if (cur.val == cur.next.val) {                cur.next = cur.next.next;            } else {                cur = cur.next;            }        }        return head;    }}

2.LeetCode82 重复元素都不要

这个题目的要求与83的区别仅仅是重复的元素都不要了。例如:

输入:head = [1,2,3,3,4,4,5]输出:[1,2,5]

这个题几乎都不需要废话来解释了。不过,需要注意的是cur.next 以及 cur.next.next 可能为空节点,需要加以判断。

class Solution {    public ListNode deleteDuplicates(ListNode head) {        if (head == null) {            return head;        }        ListNode cur = head;        while (cur.next != null) {            if (cur.val == cur.next.val) {                cur.next = cur.next.next;            } else {                cur = cur.next;            }        }        return head;    }}

三.LeetCode 1836. 从未排序链表中删除重复元素

如果将82中的排序链表改成无序的该怎么删呢?

示例:

输入:head = [3,2,2,1,3,2,4]输出: [1,4]

 分析这个题目之前,我们先造一个题:无序链表中,重复元素只保留一个,该怎么做?思路不复杂就是借助一个hash,遍历的时候一边访问元素,一边写到hashMap中,如果发生碰撞,就将当前结点删除,因此一次遍历就行了。

但是这个题要求重复的都不要,那一次遍历就不行了。我们需要扫描两遍+一个HashMap,HashMap 记录每个不同 node.val 的出现次数。第一遍扫描的时候记录每个不同 node.val 的出现次数,第二遍扫描的时候,创建一个虚拟 dummy 节点,用dummy.next去试探下一个节点是否是需要删除的节点,如果是,就直接跳过即可。

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode() {} *     ListNode(int val) { this.val = val; } *     ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */class Solution {    public ListNode deleteDuplicatesUnsorted(ListNode head) {        HashMap<Integer, Integer> map = new HashMap<>();        // dummy - 最后需要return用的        // dummy2 - 第二遍扫描的时候需要用的,因为涉及到删除操作,所以只能用.next试探        ListNode dummy = new ListNode(0);        ListNode dummy2 = dummy;        dummy.next = head;        ListNode cur = head;        while (cur != null) {            map[cur.val]++;            cur = cur.next;        }        while (dummy2.next != null) {           if (map[dummy2.next.val] > 1) {                dummy2.next = dummy2.next.next;            } else {                dummy2 = dummy2.next;            }        }        return dummy.next;    }}

好了,到此,删除元素的常见题目我们就看完了。链表相关的基础问题我们已经梳理得差不多了。后面我们再看的其他一些典型链表题目就轻松多了。

以上是关于链表12:链表中删除元素的8道题之三的主要内容,如果未能解决你的问题,请参考以下文章

链表10:链表中删除元素的8道题之一

每日一题之LeetCode237删除链表中的节点876链表的中间节点

被火车撞了都不能忘记的几道题(你会了吗?)

删除排序链表中的重复元素(简单)

LintCode之删除链表中的元素

删除有序链表中相同的元素ii