思路:
顺序遍历链表,利用两个指针,一个preNode,一个curNode,当curNode值重复时,顺序遍历找出下一个不重复的节点,后改变preNode指向这个元素。
代码:
package com.datastructure.link;
/**
* 有序链表删除重复元素
*/
public class RemoveRepeatNode {
static class Node {
int value;
Node next;
public Node(int value) {
this.value = value;
}
// 便于打印不能作用与循环链表
@Override
public String toString() {
if (this.next == null) {
return String.valueOf(this.value);
}
return this.value + "->" + this.next.toString();
}
}
/**
* 删除链表中所有重复的元素 0->1->1->2 => 0->2
*
* 新建一个临时头节点,避免头节点是重复元素时,特殊处理
*
* 返回链表头节点
*/
public static Node removeRepeat(Node head) {
if (head == null) {
return head;
}
// 临时头节点
Node root = new Node(-1);
root.next = head;
// 两个指针
Node preNode = root;
Node curNode = head;
while (curNode != null && curNode.next != null) {
// 遇到重复节点,则遍历所有相同节点,pre->next 指向 最后一个相同节点的next
if (curNode.value == curNode.next.value) {
while (curNode != null && curNode.next != null && curNode.value == curNode.next.value) {
curNode = curNode.next;
}
// curNode此时为重复元素中的最后一个元素
// 删除重复元素
preNode.next = curNode.next;
} else {
preNode = curNode;
}
// 后移curNode
curNode = curNode.next;
}
return root.next;
}
/**
* o(n)时间 有序的链表删除重复元素,保留第一个重复的元素
* 0->1->1->2 => 0->1->2
*
* 遍历链表,一个指针指向前驱节点 一个指向下一个节点
*
* @return 返回新的链表(新链表,头结点引用)
*
*/
public static Node removeRepeat1(Node head) {
if (head == null) {
throw new RuntimeException("link is empty");
}
Node root = new Node(-1);
root.next = head;
Node pre = root;
Node curNode;
while (pre != null) {
curNode = pre.next;
// 元素重复时 删除后续重复元素
if (curNode != null && pre.value == curNode.value) {
pre.next = curNode.next;
// 不重复时 pre后移一位
} else {
pre = pre.next;
}
}
return root.next;
}
/**
* o(n)时间 有序的链表删除重复元素,保留最后一个重复的元素
* 0->1->1->2 => 0->1->2
*
* 遍历链表,一个指针指向前驱节点 一个指向当前节点
*
* @return 返回新的链表(新链表,头结点引用)
*
*/
public static Node removeRepeat2(Node head) {
if (head == null) {
throw new RuntimeException("link is empty");
}
Node newHead = head;
Node preNode = newHead;
Node curNode = newHead.next;
// 当头结点与下一结点值相同,需要删除头结点及后续相同节点
if (preNode.value == curNode.value) {
while (preNode.value == curNode.value) {
preNode = preNode.next;
curNode = curNode.next;
}
newHead = preNode;
}
// 头结点与下一结点值不同
while (curNode != null && curNode.next != null) {
if (curNode.value != curNode.next.value) {
preNode = curNode;
} else {
preNode.next = curNode.next;
}
curNode = curNode.next;
}
return newHead;
}
public static void main(String args[]) {
Node head = createTestLinkedList(5, new Node(4));
// 原链表
System.out.println("origin link: " + head);
// 删除重复元素
System.out.println("remove repeat node: " + removeRepeat(head));
Node head1 = createTestLinkedList(5, new Node(4));
// 删除重复元素,保留第一个重复的元素
System.out.println("remove repeat node but left first one: " + removeRepeat1(head1));
Node head2 = createTestLinkedList(5, new Node(4));
// 删除重复元素,保留最后一个重复的元素
System.out.println("remove repeat node but left last one: " + removeRepeat2(head2));
}
private static Node createTestLinkedList(int n, Node addNode) {
Node head = new Node(0);
Node head1 = new Node(0);
head.next = head1;
Node curNode = head1;
int count = 1;
for (int i = 1; i < n; i++) {
curNode.next = new Node(i);
curNode = curNode.next;
if (i == 2 && count >= 0) {
i--;
count--;
}
}
curNode.next = addNode;
return head;
}
}