刪除鏈表中重複的結點——Java實現
1 前言
刷題也刷了一段時間了,但是總是找不到寫的東西,但就在今天,重新做這道JzOffer上的題,發現思路看着很簡單,但是其中的細節倒是不少,錯了很多次,所以想寫下這道題一起學習一下。
2 題目
2.1 題目描述
在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5
2.1 測試數據
1,1,1,1,1,1,2
1,1,1,1,1,1,1
1,1,2,2,3,3,4,4
3 自己的實現
public ListNode deleteDuplication(ListNode pHead){
if (pHead == null) {
return null;
}
//返回的頭結點
ListNode copyNode = pHead;
ListNode preNode = null;
ListNode nextNode = pHead.next;
while (nextNode != null) {
//如果相等
if (pHead.val == nextNode.val) {
int value = pHead.val;
while (nextNode.next != null && nextNode.next.val == value) {
nextNode = nextNode.next;
}
//獲得重複結點的下一個結點(注意下面多個結點也可能是相同的)(1,1,2,2,3,3,4,4)
//跳出的兩種情況:
pHead = nextNode.next;
//1.爲空(nextNode.next == null),到達鏈表尾部,又有兩種情況
if (pHead == null) {
//當preNode爲空,也就是說前面的結點都是重複的(可能是一組,也可能是多組)
//沒有不同結點,返回空
if (preNode == null) {
return null;
}
//preNode不爲空,結束(注意這裏不能再nextNode = pHead.next,pHead已經爲空了,會拋異常)
preNode.next = pHead;
return copyNode;
}
//2.值不相等時(nextNode.next.val != value)
else {
//當preNode不爲空時,連接
if (preNode != null) {
preNode.next = pHead;
}
else {
//preNode爲空時,什麼都不做(可能後面也是重複的)(1,1,2,2,3,3,4,4)
//這裏是判斷next是不是爲空
//如果爲空後不做處理,直接向下運行(因爲這裏是preNode爲空,直接向下,漏掉最後一個數據)
if (pHead.next == null) {
preNode = pHead;
copyNode = pHead;
}
}
}
}
//如果不等,preNode就不爲空
else {
//第一次,可能頭結點已經改變,賦值給copyNode
if (preNode == null) {
preNode = pHead;
copyNode = preNode;
continue;
}
preNode = pHead;
pHead = pHead.next;
}
nextNode = pHead.next;
}
//如果pHead沒有動,那說明只有一個節點
if (pHead == copyNode) {
return copyNode;
}
//preNode爲null,說明鏈表中一個不同的都沒有(preNode改變是在pHead和pNext不等的時候)
if (preNode == null) {
return null;
}
return copyNode;
}
4 JzOffer思路
public ListNode deleteDuplication(ListNode pHead) {
//這裏pHead.next==null的情況,如果交給後面會出問題
//與上面的做對比可以把後面的未移動的判斷加在這裏
if(pHead==null||pHead.next==null){
return pHead;
}
ListNode preNode = null;
ListNode pNode = pHead;
ListNode pRNode = pHead;
while (pNode!=null){
ListNode pNext = pNode.next;
//分兩種情況
//1.相等 2.不相等
//如果pNext!=null&&pNext.val==pNode.val,去重
if(pNext!=null&&pNext.val==pNode.val){
int value = pNode.val;
//保存pNode
ListNode pToBeDelete = pNode;
while (pToBeDelete!=null&&pToBeDelete.val==value){
//移動pNext
pNext = pToBeDelete.next;
pToBeDelete = pNext;
}
}
//如果pNext爲null或值不相等(與我的想法一致,只有不相等時才賦予preNode值)
else {
preNode = pNode;
}
//也是兩種情況
//1.preNode爲空 2.preNode不爲空
//只有當不同時,纔會改變preNode值
//相同時會一直賦值,最後直到null
if(preNode==null){
//對比上面改變copyNode的值
//一直跟着條件在動,篩選
pRNode = pNext;
}
else {
preNode.next = pNext;
}
pNode = pNext;
}
return pRNode;
}
對比來看的話,我的思路無疑複雜了很多,我認爲原因就是最開始就去糾結了很多細節,沒有先把一個問題的總體框架,通用的方法想到,只是注重了細節的很多種情況,最後導致顯得很複雜。先是分析大類問題,不要在小細節上糾結
這是我對比後的想法。
總的來說最開始時,需要想到的兩類情況:
1.結點值相不相同 (只有結點不同時才能改變preNode)
2.preNode是否爲空
先把總體的通用框架在心中有個大概,再在通用框架中填充細節
5 新的思路
這個解法的主要思路就是在最開始就增加一個節點,避免後面關於preNode的判斷
public ListNode deleteDuplication(ListNode pHead){
//新建節點,作爲最開始的preNode
ListNode addHeadNode = new ListNode(-1);
addHeadNode.next = pHead;
ListNode realHead = addHeadNode;
ListNode preNode = addHeadNode;
while (realHead != null) {
ListNode nextNode = realHead.next;
//同樣的判斷值是否相同
if(nextNode != null && realHead.val == nextNode.val){
ListNode pToBeDelete = nextNode;
int value = realHead.val;
while (pToBeDelete != null && pToBeDelete.val == value) {
nextNode = pToBeDelete.next;
pToBeDelete = nextNode;
}
}
//這裏略微有區別,先連接,在賦值
else {
preNode.next = realHead;
preNode = realHead;
}
//不用進行preNode爲空的判斷,永遠都不爲空
preNode.next = nextNode;
realHead = nextNode;
}
//返回我們創建頭結點的下一個結點
return addHeadNode.next;
}