鏈表常見算法題二:刪除定值節點,刪除重複元素的所有節點、反轉鏈表

LeetCode題目描述:移除鏈表元素

刪除鏈表中等於給定值 val 的所有節點。
示例:
輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

解題思路:首先保證鏈表不爲空(代碼3-6行),由於鏈表首元素未判斷(題目給的鏈表爲不帶頭結點鏈表),因此第一步先找到到第一個數據不等於val的節點(代碼8-24行)。第二步再對鏈表中的每個節點的數據進行判斷,因爲要刪除節點,所以需要每次判斷後繼節點數據和val值,如果後繼節點需要刪除,則遍歷指針不後移,若不刪除後繼指針,則遍歷指針繼續向後遍歷

當然還有操作更簡單的創建頭指針法解決,具體可以看下一道題的另一種方法實現!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val){
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode* cur=head;
    while(1)
    {
        if(cur==NULL)//當鏈表中只有被刪元素時,前面刪除完之後鏈表爲空
        {
            return NULL;
        }
        if(cur->val==val)
        {
            struct ListNode*tmp=cur;
            cur=cur->next;
            free(tmp);
        }
        else
        {
            break;//cur結點不爲空且cur結點的數據與val不等
        }
    }
    head=cur;
    for(;cur->next!=NULL;)
    {
        if(cur->next->val == val)
        {
            struct ListNode* tmp=cur->next;
            cur->next=cur->next->next;
            free(tmp);
        }
        else
        {
            cur=cur->next;
        }
    }
    return head;
}

圖解:
範例 6->6->1->2->6->3->4->5->6
在這裏插入圖片描述

LeetCode題目描述:刪除重複節點

在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。
例如,
鏈表1->2->3->3->4->4->5
處理後爲 1->2->5**
思路分析:本題其實是上一個題的變種。只不過這次的val值是變化的,只要重複該節點,則val=node->val;
首先判斷每個節點和後續節點是否重複,若重複就保存該節點的val值,然後不斷刪除後面和val值相同的節點,直到遇到和val不同的節點,說明刪除完畢,接着下次判斷。
若不重複就繼續向後遍歷判斷。
這裏有一個開始困擾的情況就是如果頭結點就是重複節點,那麼該如何刪除全部重複節點?
這裏有兩種解決辦法:

  • 先不斷刪除頭部重複節點,直到找到第一個不重複的節點作爲結束時返回的頭結點,若在刪除過程中遇到NULL說明該鏈表中所有節點均有重複;然後再對後繼節點和後繼next節點的next值判斷,若val值相同,則按照上面的解題思路刪除重複節點即可
  • 另一種就是爲了統一操作,申請一個新節點作爲頭結點,直接按照上面的解題思路遍歷就Ok了。

這裏代碼給出來兩種方法的代碼實現:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        int data=0;
        if(pHead==NULL)
        {
            return NULL;
        }
        ListNode *cur=pHead;
        ListNode*tmp=NULL;
        for(;cur!=NULL&&cur->next!=NULL;)//頭結點就出現元素重複,先找到第一個不重複的節點
        {
            if(cur->val==cur->next->val)//節點重複
            {
                data=cur->val;
                while(cur!=NULL&&cur->val==data)
                {
                    //刪除cur節點及之後與cur數據重複的節點
                    tmp=cur;
                    cur=cur->next;
                    free(tmp);
                }
                if(cur==NULL)
                {
                    return NULL;
                }
            }
            else
            {
                break;//cur和cur->next的數據不重複,說明cur節點爲第一個不重複節點
            }
        }
        pHead=cur;
        for(;cur!=NULL&&cur->next!=NULL&&cur->next->next!=NULL;)
        {
            if(cur->next->val==cur->next->next->val)//判斷cur的後繼節點是否爲重複節點
            {
                data=cur->next->val;
                while(cur->next!=NULL && cur->next->val==data)
                {
                    //刪除cur之後和data相同的節點
                    tmp=cur->next;
                    cur->next=cur->next->next;
                    free(tmp);
                }
            }
            else
            {
                cur=cur->next;
            }
        }
        return pHead;
    }
};

創建頭結點解法:

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if(pHead==NULL)
        {
            return NULL;
        }
        int data;
        ListNode*cur=(ListNode*)malloc(sizeof(ListNode));//創建一個頭結點,防止傳入的頭結點就存在重複的情況
        cur->next=pHead;
        ListNode*head=cur;//記錄頭結點,防止cur遍歷後丟失頭結點
         ListNode*tmp=NULL;
        while(cur->next!=NULL&&cur->next->next!=NULL)
        {
            if(cur->next->val==cur->next->next->val)
                //對cru之後的節點進行判斷,如果重複,進入內部循環刪除和data相同值的節點
            {
                data=cur->next->val;
                while(cur->next!=NULL&&cur->next->val==data)//刪除和data數據相同的cur->next
                {
                    tmp=cur->next;
                    cur->next=cur->next->next;
                    free(tmp);
                    tmp=NULL;
                }
            }
            else
            {
                cur=cur->next;
            }
        }
        pHead=head->next;
        free(head);//釋放19行創建的新節點
        return pHead;
    }
};

以創建頭結點法爲例作以圖解:
用例:1->1->1->2->2->3->4->4->5
在這裏插入圖片描述

LeetCode題目描述:反轉一個鏈表

反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL

解題思路:
採用指針指向掉頭的方法迭代實現,需要注意保存每次掉頭的新鏈表頭結點和舊鏈表的頭結點,,然後每次需要一個指針記錄即將調轉指向節點的後繼節點

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL)
    {
        return;
    }
    struct ListNode* cur=head->next;
    struct ListNode* tmp=head;
    tmp->next=NULL;
    while(cur!=NULL)
    {
        struct ListNode*p=cur->next;
        cur->next=tmp;
        tmp=cur;
        cur=p;
    }
    head=tmp;
    return head;
}

圖解:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章