与这个题相似的有一道题,保留原始链表中重复数字出现一次
博客地址:https://blog.csdn.net/if_i_were_a/article/details/89092123
本题的题目描述:(本题是LeetCode第82题)
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5 输出: 1->2->5
示例 2:
输入: 1->1->1->2->3 输出: 2->3
思路:与上一道题相比,这道题不同之处在于他要把所有的重复值节点都删完,前一道题的思路在于当前的值跟下一个值比较,如果重复,删除下一个,如果不重复,就继续遍历下一个元素。但是相对于这道题,当前的值即使跟下一个不相等,也有可能与之前重复过的相等。那么如何保证在这种情况下的时间复杂度为0(1)呢,可以使用一个计数器,如果有与当前节点重复的节点,删除掉重复节点之后(因为该链表是有序的,所以重复的就是当前节点的下一个),计数器的值加一。当前节点重复值删除完之后,判断当前节点是否需要删除就是判断计数器的值是否为0,如果不是0则删除该节点。然后继续遍历
有两种特殊情况,当前节点有重复在链表的头和链表的尾。当为头的时候,因为该链表是不带表头的节点,所以有两种解法,加虚拟表头结点或者分为判断是否为为表头结点,是和不是分为两种情况。对于尾节点来说,因为出循环之后还要判断尾节点是否重复过,如果重复过,删除尾节点。代码如下:
public static ListNode deleteDuplicates1(ListNode head) {
//添加一个虚拟的表头结点
ListNode tempHead = new ListNode(0);
tempHead.next = head;
//pre之前虚拟头结点,记录元素的前一个位置,如果要删除当前元素,需要前一个位置的指针
ListNode cur = head, pre = tempHead;
//计数器的初始值置为0
int count = 0;
//当前链表为空或者遍历到链表的最后一个元素时
while (cur != null && cur.next != null) {
//如果当前节点和下一个结点相等,删除下一个结点,计数值加1
if (cur.val == cur.next.val) {
cur.next = cur.next.next;
count++;
} else {
//不相等的情况下需要判断计数值是否为0来确定是否需要删除当前节点
if (count > 0) {
pre.next = cur.next;
count = 0;
} else {
pre = cur;
}
cur = cur.next;
}
}
//判断尾节点是否需要删除
if (count > 0) {
pre.next = cur.next;
}
//返回去除虚拟头结点的链表
return tempHead.next;
}
贴一个总体的代码,方便给需要的人
public class Num83 {
public static void main(String[] args) {
int[] arr = new int[]{1, 1, 1, 2, 3};
//删除链表中的重复元素,保留一个
ListNode head = new ListNode(arr);
head = deleteDuplicates1(head);
System.out.println(head.toString());
}
public ListNode deleteDuplicates(ListNode head) {
//设置一个指向当前元素的指针
ListNode current = head;
//当链表为空或者链表中遍历到最后一个元素时,出循环
while (current != null && current.next != null) {
//如果找到当前节点和它的下一个结点的值相同,删除掉下一个结点
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
//如果没有找到,当前节点后移
current = current.next;
}
}
return head;
}
public static ListNode deleteDuplicates1(ListNode head) {
//添加一个虚拟的表头结点
ListNode tempHead = new ListNode(0);
tempHead.next = head;
//pre之前虚拟头结点,记录元素的前一个位置,如果要删除当前元素,需要前一个位置的指针
ListNode cur = head, pre = tempHead;
//计数器的初始值置为0
int count = 0;
//当前链表为空或者遍历到链表的最后一个元素时
while (cur != null && cur.next != null) {
//如果当前节点和下一个结点相等,删除下一个结点,计数值加1
if (cur.val == cur.next.val) {
cur.next = cur.next.next;
count++;
} else {
//不相等的情况下需要判断计数值是否为0来确定是否需要删除当前节点
if (count > 0) {
pre.next = cur.next;
count = 0;
} else {
pre = cur;
}
cur = cur.next;
}
}
//判断尾节点是否需要删除
if (count > 0) {
pre.next = cur.next;
}
//返回去除虚拟头结点的链表
return tempHead.next;
}
static class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
public ListNode(int[] arr) {
if (arr == null || arr.length == 0)
throw new IllegalArgumentException("arr can to be empty");
this.val = arr[0];
ListNode cur = this;
for (int i = 1; i < arr.length; i++) {
cur.next = new ListNode(arr[i]);
cur = cur.next;
}
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
ListNode cur = this;
while (cur != null) {
res.append(cur.val + "->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
}
}
本函数在LeetCode上运行成功,无毒无害,可以使用哦