1. 程式人生 > 實用技巧 >25-k個一組翻轉連結串列 203-移除連結串列元素 206-反轉一個連結串列

25-k個一組翻轉連結串列 203-移除連結串列元素 206-反轉一個連結串列

題目:

給你一個連結串列,每k個節點一組進行翻轉,請你返回翻轉後的連結串列。

k是一個正整數,它的值小於或等於連結串列的長度。

如果節點總數不是k的整數倍,那麼請將最後剩餘的節點保持原有順序。

示例:

  給你這個連結串列:1->2->3->4->5

  當k= 2 時,應當返回: 2->1->4->3->5

  當k= 3 時,應當返回: 3->2->1->4->5

說明:

  你的演算法只能使用常數的額外空間。
  你不能只是單純的改變節點內部的值,而是需要實際進行節點交換。

解答:看懂了,但是自己寫有問題,自己寫的太多的判斷了,直接看解答

//指定head,然後在k段內翻轉,k段內都不為nullptr
//head-開始的頭結點
//tail-要翻轉的最後一個節點
//返回:翻轉後的頭-尾節點
pair<ListNode*, ListNode*> reverseK(ListNode* head, ListNode* tail)
{
    ListNode* pre = tail->next;//使用尾部的下一個元素作為頭
    ListNode* cur = head;
    ListNode* next = nullptr;
    while (pre != tail)
    {
        next = cur->next;
        cur
->next = pre; pre = cur; cur = next; } return{ tail, head }; } ListNode* reverseKGroup(ListNode* head, int k) { ListNode* dummy = new ListNode(0); dummy->next = head; ListNode* pre = dummy; while (head != nullptr) { ListNode* tail = pre;
for (int i = 0; i < k; i++) { tail = tail->next; if (tail == nullptr)//如果連結串列長度小於k,則直接返回該連結串列 return dummy->next; } ListNode* next = tail->next;//k段連結串列的下一個節點 pair<ListNode*, ListNode*> result = reverseK(head, tail); head = result.first; tail = result.second; //把k段的連結串列重新接回原連結串列 pre->next = head; tail->next = next; //更新pre head,用於下一段k的反轉; pre = tail; head = tail->next; } return dummy->next; }

相關題目:

203-移除連結串列元素

206-反轉一個連結串列

題目-206

反轉一個單鏈表。

示例:

輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
  你可以迭代或遞迴地反轉連結串列。你能否用兩種方法解決這道題?

解答:

程式碼一:迭代方法:

if (head == nullptr)
        return head;
    if (head->next == nullptr)//如果連結串列就一個節點,則直接返回
        return head;

    ListNode* pre = nullptr;
    ListNode* cur = head;
    ListNode* next = nullptr;
    while (cur != nullptr)
    {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }

    return pre;
}

方法二:遞迴:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/

題目-203

刪除連結串列中等於給定值val的所有節點。

示例:

輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5

解答:

自己寫的程式碼:

//連結串列中可能有多個符合的元素
ListNode* removeElements(ListNode* head, int val) 
{
    if (head == nullptr)
        return head;
    while (head!= nullptr && head->val == val)
        head = head->next;

    ListNode dummy;
    dummy.next = head;
    ListNode* tmp = &dummy;
    ListNode* pre = &dummy;
    while (tmp != nullptr)
    {
        tmp = tmp->next;
        while (tmp != nullptr && tmp->val == val)
        {
            tmp = tmp->next;
        }

        pre->next = tmp;
        pre = tmp;
    }

    return head;
}

問題:上面的程式碼沒有釋放移除節點,需要delete,修改如下:

//上面的函式沒有刪除移除的節點,
ListNode* removeElements2(ListNode* head, int val)
{
    if (head == nullptr)
        return head;
    ListNode* toBeDelete = nullptr;
    while (head != nullptr && head->val == val)
    {
        toBeDelete = head;
        head = head->next;
        if (toBeDelete != nullptr)
            delete toBeDelete;
    }

    ListNode dummy;
    dummy.next = head;
    ListNode* tmp = &dummy;
    ListNode* pre = &dummy;
    while (tmp != nullptr)
    {
        tmp = tmp->next;
        while (tmp != nullptr && tmp->val == val)
        {
            toBeDelete = tmp;
            tmp = tmp->next;

            if (toBeDelete != nullptr)
                delete toBeDelete;
        }

        pre->next = tmp;
        pre = tmp;
    }

    return head;
}

解答中的程式碼很簡潔,如下,使用了一個哨兵sentinel,而且根據當前的cur的val是否為目標值對pre進行不同的處理,邏輯比自己寫的簡單:

ListNode* removeElements3(ListNode* head, int val)
{
    ListNode* sentinel = new ListNode(0);
    sentinel->next = head;

    ListNode* pre = sentinel;
    ListNode* cur = head;
    ListNode* toBeDelete = nullptr;

    while (cur != nullptr)
    {
        if (cur->val == val)
        {
            pre->next = cur->next;
            toBeDelete = cur;
        }
        else
            pre = cur;

        cur = cur->next;

        if (toBeDelete != nullptr)
        {
            delete toBeDelete;
            toBeDelete = nullptr;
        }
    }

    ListNode* ret = sentinel->next;
    delete sentinel;
    return ret;
}