删除排序链表中重复数字节点,只保留原始链表中 没有重复出现的数字(二)
引用:原文链接:https://blog.csdn.net/dadajixxx/article/details/87551738
/*题目
* 在一个排序的链表中,存在着重复的节点,请删除该链表中重复的节点,重复的节点不保留,返回链表头指针
* 示例1:1 -> 2 -> 2 -> 3 -> 3 -> 4 -> 5 -------->删除后: 1 -> 4 -> 5
* 示例2: 1->1->1->2->3 --------->删除后:2->3
*
* */
解法1:
原文链接:https://blog.csdn.net/if_i_were_a/article/details/89093043
思路:与上一道题相比,这道题不同之处在于他要把所有的重复值节点都删完,前一道题的思路在于当前的值跟下一个值比较,如果重复,删除下一个,如果不重复,就继续遍历下一个元素。但是相对于这道题,当前的值即使跟下一个不相等,也有可能与之前重复过的相等。那么如何保证在这种情况下的时间复杂度为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;
}
-----------------------------------------------解法1的完整代码------start-----------------------------------------------
原文链接:https://blog.csdn.net/if_i_were_a/article/details/89093043
public class Num83 {
public static void main(String[] args) {
int[] arr = new int[]{1, 1, 1, 2, 3, 5};
//删除链表中的重复元素,保留一个
ListNode head = new ListNode(arr);
head = deleteDuplicates1(head);
System.out.println(head.toString());
}
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();
}
}
}
------------------------------------------------解法1完整代码--------end------------------------------------------------
解法2:
/*思路
* 遍历节点的同时判断当前节点与下一个节点是否相同,如果相同则删除,
* 删除方法 使用相同节点的前一个节点,指向相同节点的下一个节点如图
*
* */
public class offer57 {
class ListNode{
int val;
ListNode next=null;
public ListNode(){ }
public ListNode(int val){
this.val=val;
}
}
public ListNode deleteDeplication(ListNode pHead){
if (pHead == null) return null;
//注意备用头结点,头结点可能被删除
ListNode first = new ListNode(-1);
first.next = pHead;
ListNode p = pHead;
//前节点
ListNode preNode = first;
while (p != null && p.next != null){
if (p.val == p.next.val){ //两节点相等
int val = p.val; //记录val用于判断后面节点是否重复
while(p != null && p.val == val){ //这一步用于跳过相等的节点,用于删除
p = p.next;
}
preNode.next = p; //删除操作,前节点的next直接等于现在的节点,把中间的节点直接跨过
}else {
preNode = p;
p = p.next;
}
}
return first.next;
}
}
解法3:双指针法(也可以说是三指针法,设置的头结点需要参与元素链接,最后还需要输出) 设置一个新的头结点,使得链表元素进行链接和输出 当前后两个指针相同时,移动下一个指针到两个元素不相同,然后使用设置的头结点进行链接,得以越过相同元素 如果两个指针不相同,就移动处理,指针跟随
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) return null;
ListNode dummy = new ListNode(-1); //为链表创建一个新的头,return dummy.next 来带领整个链表
dummy.next = head;
ListNode current = head;
ListNode index = dummy;
//index在前面,所以判断index是否为null 就行
while(current != null && current.next!= null) {
//相等,将index移动向下一位
if(current.val == current.next.val) {
while(current.next!= null && current.val == current.next.val) {current = current.next;}
index.next = current.next;
current = current.next;
} else {
index = current;
current = current.next;
}
}
return dummy.next;
}
}
解法4:三指针法(利用三个指针和标志位flag进行处理)
public ListNode deleteDuplicates(ListNode head) {
ListNode pre = null;
ListNode current = head;
while (current != null) {
ListNode nex = current.next; //通过while循环始终让nex作为最快的指针,注意进行null的判断
boolean flag = false; //使用flag作为nex和cur的标志位
while (nex != null && current.val == nex.val) {
flag = true;
nex = nex.next;
}
//对重复元素进行处理
if (flag) {
//判断不是刚开始,进行和nex结点的连接
if (pre != null) {
pre.next = nex;
} else { //头部
head = nex;
}
current = nex;
} else { //对非重复元素进行连接和跳跃
pre = current;
current = current.next;
}
}
//返回头指针
return head;
}
解法5:递归方法
public static ListNode deleteDuplicates(ListNode head) {
//baseCase
if (head == null || head.next == null) { return head;}
ListNode next = head.next;
//如果是这种情况
// 1 --> 1 --> 1 --> 2 --> 3
// head next
//1.则需要移动next直到出现与当前head.value不相等的情况(含null)
//2.并且此时的head已经不能要了,因为已经head是重复的节点
//--------------else-------------
// 1 --> 2 --> 3
// head next
//3.如果没有出现1的情况,则递归返回的节点就作为head的子节点
if (head.value == next.value) {
//1
while (next != null && head.value == next.value) { next = next.next; }
//2
head = deleteDuplicates(next);
} else {
//3
head.next = deleteDuplicates(next);
}
return head;
}
}
}
解法6:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class
Solution {
public
ListNode deleteDuplicates(ListNode head) {
ListNode dummy =
new
ListNode(
0
);
dummy.next = head;
ListNode p = head;
ListNode q = dummy;
boolean
isDel =
false
;
while
(p !=
null
){
if
(p.next !=
null
&& p.val == p.next.val ){
isDel =
true
;
p.next = p.next.next;
}
else
{
p = p.next;
if
(isDel){
q.next = p;
isDel =
false
;
}
else
{
q = q.next;
}
}
}
return
dummy.next;
}
}
解法7:
原文链接:https://blog.csdn.net/weixin_43573824/article/details/88603222
解题思路:
- 先虚拟一个头节点,这个头节点指向给定的头节点。
- 如果给定的头节点的值与下一个节点的值相等,就向后遍历,找到跟当前节点值不同的节点(temp)。
- 将虚拟头节点的下一个节点,指向temp。
- 以此思路往后遍历即可。
public static ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) return head;
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode first = dummyHead;
while (head != null && head.next != null) {
if (head.val == head.next.val) {
int value = head.val;
while (head != null && head.val == value) {
head = head.next;
}
first.next = head;
}else {
first = head;
head = head.next;
}
}
return dummyHead.next;
}