链表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道题之三的主要内容,如果未能解决你的问题,请参考以下文章