刪除鏈表中重複的結點——Java實現

刪除鏈表中重複的結點——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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章