【剑指offer】18.2 删除链表中重复的结点

206 阅读2分钟

题目描述

在这里插入图片描述

// 18.2 删除链表中重复的结点

// 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,
// 重复的结点不保留,返回链表头指针。例如,链表1->2->3->3->4->4->5
// 处理后为 1->2->5

题解


//////////////////////////////// 双指针 ////////////////////////////
// 牛客


// 运行时间:14ms
// 占用内存:9916k
public class Solution{
	public ListNode deleteDuplication(ListNode pHead) {
		if (pHead == null || pHead.next == null)
			return pHead;
		ListNode dummy = new ListNode(-1);
		dummy.next = pHead;
		
		ListNode pre = dummy;
		ListNode cur = pHead;
		cur = cur.next;  // 先让cur右移一格,我们比较的是pre.next和cur
		while (cur != null) {
			// 如果发现重复结点
			if (pre.next.val == cur.val) {
				if (cur.next == null) {  // 判断cur右移后是否到达链表尾
					pre.next = null;  // 到达链表尾,就直接让pre.next指向null
					break;  // 打断循环,返回结果
				}
				
				cur = cur.next;  // cur继续右移(直到重复串的尾部)
				// 如果右移后cur到达重复子串的尾部
				if (pre.next.val != cur.val) { 
					pre.next = cur;  // 直接令pre.next指向cur
					cur = cur.next;  // cur右移一格
				}
			}
			// 未发现重复结点,一起右移
			else {  
				pre = pre.next;
				cur = cur.next;
			}
		}
		return dummy.next;  // 不要返回pHead头节点了
	}
}


// 简化版
// 运行时间:14ms
// 占用内存:9984k
public class Solution{
	public ListNode deleteDuplication(ListNode pHead) {
		if (pHead == null || pHead.next == null)
			return pHead;
		ListNode dummy = new ListNode(-1);
		dummy.next = pHead;
		
		ListNode pre = dummy;
		ListNode cur = pHead;
		while (cur != null) {
			// 如果发现重复结点
			if (cur.next != null && cur.next.val == cur.val) {
				while (cur.next != null && cur.next.val == cur.val) {
					cur = cur.next;  // cur继续右移(直到重复串的尾部)
				}
				// 再前进一格
				cur = cur.next;
				pre.next = cur;
			}
			// 未发现重复结点,一起右移
			else {  
				pre = pre.next;
				cur = cur.next;
			}
		}
		return dummy.next;
	}
}

/////////////////////////////////// 递归法 //////////////////////////
// 牛客
// 运行时间:11ms
// 占用内存:9948k
public class Solution {
	public ListNode deleteDuplication(ListNode pHead) {
		// 未开始递归时,pHead是头结点,开始递归后,pHead为遍历结点

		if (pHead == null || pHead.next == null) {
			return pHead;
		}
		// 1.未开始递归时,取头结点next记为next
		// 2.开始递归后,pHead为遍历节点,且实际被pHead.next指向,
		// next为pHead.next,所以实际被pHead.next.next指向
		ListNode next = pHead.next;  
		// 1.未开始递归时,若头结点出现重复,则if成立,
		// 直接开始while循环找重复子串尾结点
		// 2.开始递归后,如果pHead和next的val相等
		// 开始while循环找重复子串尾结点
		if (pHead.val == next.val) {
			// while循环继承了if的判断,同时保证next(pHead.next.next)不为null
			while (next != null && pHead.val == next.val) 
				next = next.next;  // next右移,直到遍历到重复子串的下一个结点
			// 返回deleteDuplication递归调用
			// 递归到底并返回之后,由于next被pHead.next指向,所以
			// next循环右移就已经剔除了重复结点
			return deleteDuplication(next);  
		}
		// 若头结点未出现重复,else成立
		else {
			// 令pHead.next指向eleteDuplication的递归调用,输入pHead.next
			// 假设链表一直没有重复节点,函数输入pHead实际是被上一个递归
			// 的pHead.next指向,再递归取pHead.next,对于上一次递归
			// 就是pHead.next.next,一直这样下去,实际就是遍历了整个
			// 链表一次。
			pHead.next = deleteDuplication(pHead.next);
			return pHead;
		}
	}
}